以前很少使用智能指针,在单线程的情况下,对象的存活周期都好确定,而在多线程中,思考对象存活周期是极其复杂的,初学的时候没觉得多线程有多难,后来写过和阅读过很多多线程代码,发现跨线程的对象的存活周期是最难确定,很少确定到底在什么地方delete,手写过一遍muduo网络库,再次看muduo网络库这本书,对C++11智能指针又有了新的理解。
书中提到shared_ptr相当于强铁丝,weak_ptr相当于细铁丝。这个要怎么理解呢?可以用weak_ptr的lock来判断shared_ptr对象是否还存活,利用lock来判断是否可以进行提升
shared_ptr<A> ptr = make_shared<A>();
std::function<void()> fun = std::bind(&A::fun,ptr);
cout << ptr.use_count() << endl;
在fun中利用bind绑定函数的时候,shared_ptr也是的引用计数器也是会自动加1的。会自动复制一份拷贝的。
一种错误的使用sharedptr的情况是
#include <iostream>
#include <functional>
#include <memory>
#include <vector>
using namespace std;
class A{
public:
A() = default;
void fun(){}
static vector<shared_ptr<A>> local_ptr;
//static vector<weak_ptr<A>> local_ptr;
};
vector<shared_ptr<A>> A::local_ptr;
//vector<weak_ptr<A>> A::local_ptr;
int main(){
{
shared_ptr<A> ptr = make_shared<A>();
A::local_ptr.emplace_back(ptr);
cout << "local_ptr use_count " << A::local_ptr[0].use_count() << endl;
}
cout << "local_ptr size " << A::local_ptr.size()<< endl;
cout << A::local_ptr[0].use_count() << endl;
return 0;
}
A类的容器用了shared_ptr保存,导致就算ptr离开了他所在的作用域,ptr指向的内存也不会释放掉,因为local_ptr还保存着一份ptr的值。
正确的做法
上述代码应该使用weak_ptr,如果对象还活着,可以用lock()来提升他,不过这样也会造成浪费,ptr离开了他的作用域,可以正常释放ptr指向的资源,但是因为并没有在local_ptr中删掉他,通俗的讲就是local_ptr的下标0还是ptr这个对象,尽管他指向的对象是被delete掉了,解决这个办法就是给ptr一个指定的自定义删除器,让删除器去把ptr占的位置给delete掉
在跨线程使用对象是会遇到各种各样的险态,需要我们仔细的思考各种竞争情况,多多思考,多多总结