1.概要
2.内容
C++ 智能指针是 C++11 引入的现代内存管理工具,用于自动化管理动态分配的内存,避免内存泄漏和悬垂指针问题。以下是智能指针的核心知识点和用法指南:
一、智能指针类型
-
unique_ptr(独占所有权)
- 特点:同一时间只能有一个 unique_ptr 拥有对象所有权
- 用途:替代裸指针管理独占资源
std::unique_ptr<int> ptr(new int(42)); // 转移所有权 std::unique_ptr<int> ptr2 = std::move(ptr); -
shared_ptr(共享所有权)
- 特点:通过引用计数实现多指针共享同一对象
- 注意:循环引用会导致内存泄漏
auto ptr1 = std::make_shared<int>(10); auto ptr2 = ptr1; // 引用计数+1 -
weak_ptr(弱引用)
- 特点:不增加引用计数,用于解决 shared_ptr 循环引用
std::weak_ptr<int> weak = ptr1; if (auto tmp = weak.lock()) { // 检查有效性 // 安全使用 *tmp }
二、核心优势
- 自动内存回收:离开作用域自动释放内存
- 异常安全:无需手动 delete
- 明确所有权语义:编译期检查所有权规则
三、最佳实践
-
优先使用 make_shared/make_unique(C++14 起)
auto ptr = std::make_shared<MyClass>(arg1, arg2);避免裸指针与智能指针混用
// 错误:可能导致重复释放 std::shared_ptr<int> p1(new int(5)); int* p2 = p1.get(); delete p2; // 危险!循环引用解决方案
// 错误:可能导致重复释放 std::shared_ptr<int> p1(new int(5)); int* p2 = p1.get(); delete p2; // 危险! -
自定义删除器
// 文件指针示例 std::unique_ptr<FILE, decltype(&fclose)> file_ptr( fopen("test.txt", "r"), fclose );
四、性能注意
- shared_ptr 有额外开销(控制块、原子操作)
- unique_ptr 性能接近裸指针
- 循环引用检测工具:Valgrind、AddressSanitizer
智能指针是现代 C++ 资源管理的基石,合理使用能显著提升代码安全性和可维护性。建议新项目优先使用智能指针,仅在必要时使用裸指针(如与 C 接口交互)。
3.关联链接
4.关联知识
1.c++ 智能指针使用场景举例
智能指针的核心优势在于明确所有权语义和自动内存管理,以下是针对不同场景的智能指针使用指南及代码示例:
一、unique_ptr 适用场景
特点:独占所有权,不可复制,只能移动
适用场景:
- 工厂模式(转移所有权)
std::unique_ptr<Image> createImage(int type) {
if (type == 1) return std::make_unique<JpegImage>();
else return std::make_unique<PngImage>();
}
// 使用方
auto img = createImage(1); // 所有权转移
- 容器存储动态对象
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>());
shapes.push_back(std::make_unique<Square>());
- 资源管理(文件/网络句柄)
void processFile() {
auto file = std::unique_ptr<FILE, decltype(&fclose)>(
fopen("data.txt", "r"),
fclose
);
if (!file) throw std::runtime_error("Open failed");
// 使用文件...
} // 自动关闭文件
二、shared_ptr 适用场景
特点:共享所有权,引用计数管理
适用场景:
- 共享缓存系统
class ImageCache {
public:
std::shared_ptr<Image> getImage(const std::string& id) {
// 从缓存或加载新图像
return std::shared_ptr<Image>(new Image(id), [this](Image* p){
// 自定义删除逻辑(如从缓存移除)
});
}
};
// 多个组件共享图像
auto img1 = cache.getImage("logo");
auto img2 = img1; // 引用计数+1
- 观察者模式
class Subject {
std::vector<std::weak_ptr<Observer>> observers;
public:
void attach(std::shared_ptr<Observer> obs) {
observers.push_back(obs);
}
void notify() {
for (auto& wp : observers) {
if (auto sp = wp.lock()) {
sp->update();
}
}
}
};
三、weak_ptr 适用场景
特点:不控制生命周期,用于观察 shared_ptr
适用场景:
- 解决循环引用
class Parent;
class Child {
std::weak_ptr<Parent> parent; // 弱引用
public:
void setParent(std::shared_ptr<Parent> p) {
parent = p;
}
};
class Parent {
std::shared_ptr<Child> child;
public:
void setChild(std::shared_ptr<Child> c) {
child = c;
c->setParent(shared_from_this()); // 需要 enable_shared_from_this
}
};
- 缓存临时访问
class Parent;
class Child {
std::weak_ptr<Parent> parent; // 弱引用
public:
void setParent(std::shared_ptr<Parent> p) {
parent = p;
}
};
class Parent {
std::shared_ptr<Child> child;
public:
void setChild(std::shared_ptr<Child> c) {
child = c;
c->setParent(shared_from_this()); // 需要 enable_shared_from_this
}
};
四、选择策略总结
| 智能指针 | 适用场景 | 典型特征 |
|---|---|---|
| unique_ptr | 独占所有权、性能敏感场景 | 不可复制,零额外开销 |
| shared_ptr | 共享所有权、需要自动回收 | 引用计数,线程安全 |
| weak_ptr | 观察共享对象、打破循环引用 | 不影响引用计数,需配合 lock() |
实际开发中:
- 优先使用 unique_ptr 作为默认选择
- 需要共享所有权时才使用 shared_ptr
- 用 weak_ptr 作为 shared_ptr 的观察者或解决循环依赖
- 避免混合使用裸指针和智能指针管理同一对象
2.unique_ptr 我有个类A 如何用unique_ptr创建一个A的指针
使用 unique_ptr 创建类 A 的指针有两种推荐方式,以下是具体示例:
#include <memory>
class A {
public:
void doSomething() { /* ... */ }
int value = 42;
};
int main() {
// 方式1:使用 make_unique (推荐,C++14起)
auto ptr1 = std::make_unique<A>();
ptr1->doSomething();
ptr1->value = 100;
// 方式2:直接构造 unique_ptr
std::unique_ptr<A> ptr2(new A());
ptr2->value = 200;
// 所有权转移示例
auto ptr3 = std::move(ptr1); // ptr1变为nullptr
ptr3->doSomething();
return 0;
}
关键说明:
std::make_unique<A>()是首选方式(C++14及以上),因为它:- 自动推导类型,避免显式写
new - 异常安全(若构造函数抛出异常,内存不会泄漏)
- 代码更简洁
- 自动推导类型,避免显式写
- 直接构造方式
std::unique_ptr<A>(new A())适用于:- 需要传递自定义删除器
- 需要使用已有的裸指针初始化
- 访问成员:
- 使用箭头运算符
->访问成员函数/变量 - 也可以通过
ptr.get()获取原始指针(谨慎使用)
- 使用箭头运算符
最佳实践:
- 优先使用
make_unique - 避免混合使用
unique_ptr和裸指针管理同一对象 - 需要转移所有权时使用
std::move() - 通过
if (ptr)检查指针是否为空
注意:如果编译器不支持 C++14,需使用方式2,但建议升级编译器以获得更好的安全性。
551

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



