一 unique_ptr独占智能指针
独占所有权,同一时间只能有一个unique_ptr指向这块堆内存,禁止拷贝,只允许移动。
不能拷贝:unqiue_ptr<int> p2 = p1;编译报错;
可以移动:unique_ptr<int> p2 = move(p1);移动后p1变成空,p2接管资源;
生命周期:出作用域,自动调用delete释放内存;
示例代码:
#include <iostream>
#include <memory>
using namespace std;
int main()
{
// 创建unique_ptr,管理堆上int
unique_ptr<int> p1(new int(100));
cout << *p1 << endl;
// unique_ptr<int> p2 = p1; // ❌ 编译报错!禁止拷贝,独占
unique_ptr<int> p2 = move(p1); // ✅ 移动所有权
cout << *p2 << endl;
// p1 现在是空指针,不能再使用*p1
return 0;
} // 出作用域,p2销毁,自动释放堆内存,不用手动delete
要点:
1.底层:析构的时候直接释放内存,没有引用计数,开销很小;
2.适用场景:资源只需要一个管理者(绝大多数场景优先用unique_ptr);
3.C++14推荐写法:auto p = make_unique<int>(100);
二 shared_ptr共享智能指针
共享所有权,维护引用计数;每多一个shared_ptr指向同一块内存,计数+1;对象析构计数-1;引用计数减到0,释放堆内存。
引用计数:单独存放在堆上,不是存在对象内部;
拷贝允许:拷贝时引用计数+1;
移动:原指针置空,计数不变;
示例代码:
#include <iostream>
#include <memory>
using namespace std;
int main()
{
shared_ptr<int> p1 = make_shared<int>(200); // 计数=1
cout << p1.use_count() << endl; // use_count查看引用计数
shared_ptr<int> p2 = p1; // ✅ 允许拷贝,共享资源,计数=2
cout << p2.use_count() << endl;
p1.reset(); // p1放弃管理,计数=1
cout << p2.use_count() << endl;
return 0;
} // 函数结束p2析构,计数变成0,释放内存
致命问题:循环引用(内存泄漏)
两个对象A,B,A里面存shared_ptr<B>,B里面存shared_ptr A持有B,B持有A。两个对象析构的时候,引用计数都减到1,永远不为0,内存永远不释放。
struct B;
struct A{
shared_ptr<B> b_ptr;
~A(){cout << "A析构"<<endl;}
};
struct B{
shared_ptr<A> a_ptr;
~B(){cout << "B析构"<<endl;}
};
int main()
{
shared_ptr<A> a = make_shared<A>();
shared_ptr<B> b = make_shared<B>();
a->b_ptr = b;
b->a_ptr = a;
// 出main,a、b析构,但是内部互相持有,引用计数=1
// A、B的析构函数**不会执行,内存泄漏!**
return 0;
}
运行结果:不会打印A析构,B析构,内存泄漏;
解决方案:把其中一个shared_ptr改为weak_ptr;
三 weak_ptr弱引用
不增加shared_ptr的引用计数,不拥有资源,只是“旁观”shared_ptr管理的对象
weak_ptr不能直接解引用访问对象,必须调用.lock(),返回一个临时shared_ptr;
lock()底层是如何操作的
拿到 weak_ptr 保存的控制块地址(weak_ptr 内部只存控制块指针 + 对象指针,不持有对象)
原子操作读取 use_count,判断 use_count > 0
-
如果 use_count == 0:对象已经被释放 → 直接返回空的shared_ptr
-
如果 use_count > 0:尝试原子地把 use_count +=1(原子!防止多线程并发释放)
构造一个新的 shared_ptr,把对象指针、控制块指针交给这个新 shared_ptr 返回
整个过程是原子的,防止多线程下 “判断完还没加计数,对象就被别的线程释放”
可以用.expired()判断资源是否已经被释放;
专门解决shared_ptr循环引用问题;
修复上面循环引用代码(把A内部的shared_ptr<B>改为weak_ptr<B>)
#include <iostream>
#include <memory>
using namespace std;
struct B;
struct A{
weak_ptr<B> b_ptr; // 弱指针!不增加引用计数
~A(){cout << "A析构"<<endl;}
};
struct B{
shared_ptr<A> a_ptr;
~B(){cout << "B析构"<<endl;}
};
int main()
{
shared_ptr<A> a = make_shared<A>();
shared_ptr<B> b = make_shared<B>();
a->b_ptr = b; // weak_ptr赋值,b的引用计数不会+1
b->a_ptr = a;
return 0;
}
// 输出:A析构 B析构,内存正常释放!
当main函数结束:
1.b析构,B内部a_ptr计数减1,a的引用计数变成0->A对象释放;
2.A释放后,weak_ptr自动失效,没有指针再持有B,B的引用计数变成0->B释放。
使用weak_ptr访问对象示例:
shared_ptr<int> s = make_shared<int>(666);
weak_ptr<int> w = s;
// cout << *w; // ❌ weak_ptr不能直接解引用
shared_ptr<int> tmp = w.lock(); // 拿到临时shared_ptr
if(tmp != nullptr)
{
cout << *tmp << endl;
}
网硕互联帮助中心


评论前必须登录!
注册