一、场景:手动管理 vs 智能指针管理
| 方式 | 特点 | 内存管理 |
|---|---|---|
| ❌ 普通指针 | 需要手动 new / delete | 容易泄漏或悬空 |
| ✅ 智能指针 | 自动释放 | 安全、简洁 |
二、unique_ptr(独占所有权)
基本用法对比
不用智能指针
Foo* p = new Foo();
// 使用
p->doSomething();
// 手动释放
delete p;
用 unique_ptr
#include <memory>
auto p = std::make_unique<Foo>(); // 推荐写法(C++14+)
// 使用
p->doSomething();
// 离开作用域自动 delete,无需手动释放
函数传参
void func(std::unique_ptr<Foo> p); // 独占所有权传入(会转移)
func(std::move(p)); // 调用后p变空
函数返回
std::unique_ptr<Foo> createFoo() {
return std::make_unique<Foo>(); // 自动返回(移动语义)
}
适用场景:对象只会被一个地方使用;生命周期明确。

三、shared_ptr(共享所有权)
基本用法对比
不用智能指针
Foo* p1 = new Foo();
Foo* p2 = p1; // 指向同一对象
delete p1; // ❌ p2 变悬空指针
用 shared_ptr
#include <memory>
auto p1 = std::make_shared<Foo>();
auto p2 = p1; // 引用计数 +1
p1->doSomething();
p2->doSomething();
// 作用域结束时,最后一个shared_ptr销毁对象
函数传参
void func(std::shared_ptr<Foo> p) {
p->doSomething();
}
auto obj = std::make_shared<Foo>();
func(obj); // 引用计数 +1,安全共享
函数返回
std::shared_ptr<Foo> createFoo() {
return std::make_shared<Foo>();
}
auto p = createFoo(); // 调用者和返回者共享同一对象
适用场景:资源被多个模块共享使用,生命周期由引用计数控制。

四、weak_ptr(弱引用,不拥有对象)
基本用法对比
不用智能指针(容易循环引用)
struct A;
struct B {
A* pa;
};
struct A {
B* pb;
};
手动管理极易出现重复释放或内存泄漏。
用 shared_ptr + weak_ptr
#include <memory>
#include <iostream>
struct A;
struct B;
struct A {
std::shared_ptr<B> pb;
~A() { std::cout << "A析构\n"; }
};
struct B {
std::weak_ptr<A> pa; // 不增加引用计数
~B() { std::cout << "B析构\n"; }
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->pb = b;
b->pa = a;
} // ✅ 自动析构,不会内存泄漏
检查对象是否还存在
std::shared_ptr<Foo> sp = std::make_shared<Foo>();
std::weak_ptr<Foo> wp = sp;
if (auto temp = wp.lock()) { // 安全访问
temp->doSomething();
} else {
std::cout << "对象已销毁\n";
}
适用场景:
-
避免循环引用(如父子节点、观察者模式)
-
想“知道对象是否还活着”,但不想影响生命周期
-

五、综合示例(函数 + 变量 + 对象)
#include <iostream>
#include <memory>
struct Foo {
Foo(int x) : val(x) { std::cout << "构造 " << val << "\n"; }
~Foo() { std::cout << "析构 " << val << "\n"; }
void show() { std::cout << "值:" << val << "\n"; }
int val;
};
// 使用 unique_ptr(独占)
void takeUnique(std::unique_ptr<Foo> p) {
p->show();
}
// 使用 shared_ptr(共享)
void takeShared(std::shared_ptr<Foo> p) {
std::cout << "use_count=" << p.use_count() << "\n";
p->show();
}
int main() {
// --- unique_ptr ---
auto up = std::make_unique<Foo>(1);
takeUnique(std::move(up)); // 所有权转移
// up 已为空
// --- shared_ptr ---
auto sp1 = std::make_shared<Foo>(2);
auto sp2 = sp1; // 引用计数+1
takeShared(sp2); // 临时+1
std::cout << "主函数计数=" << sp1.use_count() << "\n";
// --- weak_ptr ---
std::weak_ptr<Foo> wp = sp1;
sp1.reset(); // 释放对象(计数变0,析构)
if (wp.expired()) std::cout << "weak_ptr检测:对象已销毁\n";
}
六、总结口诀表
| 类型 | 所有权 | 能否复制 | 能否共享 | 是否自动释放 | 常见用途 |
|---|---|---|---|---|---|
unique_ptr | 独占 | ❌(只能移动) | ❌ | ✅ | 独占资源、局部对象 |
shared_ptr | 共享 | ✅ | ✅ | ✅(计数归零时) | 资源共享 |
weak_ptr | 无(观察) | ✅ | ✅ | ❌ | 防循环引用、检测有效性 |
记忆口诀:
独占用
unique_ptr共用用
shared_ptr只看不用用
weak_ptr

被折叠的 条评论
为什么被折叠?



