C++11 引入了 3 个智能指针类型:
std::unique_ptr<T>:独占资源所有权的指针;std::shared_ptr<T>:共享资源所有权的指针,它的原理是使用引用计数实现对同一块内存的多个引用,在最后一个引用被释放时,指向的内存才释放;std::weak_ptr<T>:共享资源的观察者,需要和std::shared_ptr一起使用,不影响资源的生命周期。
1. std::unique_ptr
{
std::unique_ptr<int> uptr = std::make_unique<int>(200);
std::unique_ptr<int> uptr1 = uptr; // 编译错误,std::unique_ptr<T> 是 move-only 的
std::unique_ptr<int> uptr2 = std::move(uptr); // 转为右值后
assert(uptr == nullptr);
}
2. std::shared_ptr
{
std::shared_ptr<int> sptr = std::make_shared<int>(200);
assert(sptr.use_count() == 1); // 此时引用计数为 1
{
std::shared_ptr<int> sptr1 = sptr;
assert(sptr.get() == sptr1.get());
assert(sptr.use_count() == 2); // sptr 和 sptr1 共享资源,引用计数为 2
}
assert(sptr.use_count() == 1); // sptr1 已经释放
}
// use_count 为 0 时自动释放内存
错误用法1:退出{ }p1、p2都会对p0析构,导致p0被删除两次,报错;
{
int *p0 = new int(1);
shared_ptr<int> p1(p0);
shared_ptr<int> p2(p0);
}
错误用法2:循环引用;
struct Father{
shared_ptr<Son> son_;
};
struct Son{
shared_ptr<Father> father_;
};
int main(){
auto father = make_shared<Father>();
auto son = make_shared<Son>();
father->son_ = son;
son->father_ = father;
return 0;
}
main 函数退出之前,Father_obj、Son_obj的引用计数都是 2,退出main后,引用计数为1,导致对象没法被销毁,从而引起内存泄漏。
3. std::weak_ptr
std::weak_ptr为弱引用指针(std::shared_ptr是强引用指针),弱引用指针不会增加引用计数。
使用std::weak_ptr修正错误用法2:
struct Father{
shared_ptr<Son> son_;
};
struct Son{
weak_ptr<Father> father_;
};
int main(){
auto father = make_shared<Father>(); // father ptr points to a Father obj
auto son = make_shared<Son>();
father->son_ = son;
son->father_ = father;
return 0;
}
- 退出
main之前,Son_obj引用数为2,Father_obj引用为1; - 退出
main后,son 指针被销毁 ⇒Son_obj引用数为1;
father 指针被销毁 ⇒father_obj引用数为0; father_obj引用数为0⇒Father_obj被析构 ⇒Father_obj.son被销毁⇒Son_obj引用数为0⇒Son_obj被析构;- 最终
father_obj与Son_obj被正常析构。
本文介绍了C++11引入的三种智能指针:std::unique_ptr(独占资源所有权)、std::shared_ptr(共享资源所有权,使用引用计数管理内存)和std::weak_ptr(共享资源的观察者,避免循环引用问题)。文章列举并解析了std::shared_ptr的两个常见错误用法,包括双删问题和循环引用导致的内存泄漏。

2781

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



