shared_ptr简单应用

shared_ptr 是C++共享指针,往往应用在动态分配内存的场景下。相较于new操作符的优势在于shared_ptr共享指针可以自动进行动态内存释放,而new必须与delete配合使用,否则会造成内存泄露。

一个好的建议是:坚持只使用智能指针,就可以避免忘记delete造成的内存泄露,避免同一块内存被释放两次的问题。对于一块内存,只有在没有任何智能指针指向它的情况下才会自动释放它。

shared_ptr还可以作为class的成员,以使该class的对象能够共享数据。下面的代码进行了一下简单的实践。

#include<iostream>#include<memory>#include<initializer_list>#include<vector>usingnamespacestd;classintBlob{friendostream&printBlob(ostream&os,intBlob&blob);public:explicitintBlob(initializer_list<int>il):data_(make_shared<vector<int>>(il)){std::cout<<"列表初始化构造函数"<<std::endl;}intBlob():data_(make_shared<vector<int>>()){std::cout<<"默认构造函数"<<std::endl;}intBlob(constintBlob&blob):data_(blob.data_){std::cout<<"拷贝构造函数"<<std::endl;}intBlob&operator=(constintBlob&b2){data_=b2.data_;return*this;}~intBlob(){std::cout<<"析构函数"<<std::endl;}voidpush_back(intd);voidprintUseCount(){std::cout<<"shared_ptr used count: "<<data_.use_count()<<endl;}private:shared_ptr<vector<int>>data_;};voidintBlob::push_back(intd){data_->push_back(d);}ostream&printBlob(ostream&os,intBlob&blob){os<<"blob data size:"<<blob.data_->size()<<std::endl;for(auto&d:*(blob.data_)){os<<d<<" ";}os<<std::endl;}intmain(){intBlob B1{0,1,2,3,4,5,6,7,8,9};{intBlobB2(B1);printBlob(cout,B1);//这里说明友元函数可以访问class的私有成员printBlob(cout,B2);B1.printUseCount();B2.printUseCount();B2.push_back(10);}//出该作用域前B2对象会被析构,shared_ptr内部的计数器自动减1,因此会看到下面的B1.printUseCount()变成了1B1.printUseCount();printBlob(cout,B1);//B2对data所指的vector进行了push_back,虽然这里B2已经被析构了,但是B1所用的vector也有了10//可以看出B1和B2确实共享了数据intBlob B3;printBlob(cout,B3);return0;}

运行结果

列表初始化构造函数 拷贝构造函数 blob data size:10 0 1 2 3 4 5 6 7 8 9 blob data size:10 0 1 2 3 4 5 6 7 8 9 shared_ptr used count: 2 shared_ptr used count: 2 析构函数 shared_ptr used count: 1 blob data size:11 0 1 2 3 4 5 6 7 8 9 10 默认构造函数 blob data size:0 析构函数 析构函数

shared_ptr可以使用普通的内置指针进行初始化,但是这样做是有风险的。如下:

int*p=newint(50);shared_ptr<int>p1_shared(p);shared_ptr<int>p2_shared(p);shared_ptr<int>p3_shared(p1_shared);std::cout<<p1_shared.use_count()<<" "<<p2_shared.use_count()<<" "<<p3_shared.use_count()<<std::endl;

打印结果如下:

2 1 2

实际上p1_shared、p2_shared和p3_shared都指向同一个int对象,所以use_count都为3才是正确的。但是如果用一个内置指针单独去初始化不同的shared_ptr,则智能指针内部的计数器是感受不到的。因此在释放内存的时候就可能产生悬空指针。p3_shared因为是用p1_shared初始化的,所以它和p1_shared的use_count打印为2,也就是它们都不知道还有一个p2_shared也指向了同一个内存。

因此不要混用普通指针和智能指针。