1、C++11标准库提供两大类型的smart pointer:
shared_ptr实现共享式拥有概念。多个smart pointer既共享也拥有对象,这个拥有的意思表面上可以理解为计数器的个数。在这里特别强调是为了区分后面讲到的weak_ptr。当最后一个引用的指针被销毁时,这个对象也被析构(这里也可以理解为当计数器的个数为0时,对象被析构)。
unique_ptr实现独占式拥有概念。保证在同一时间内只有一个smart pointer可以指向该对象。可以将移交拥有权给其他smart pointer。
2、在这里特别提醒一点,auto_ptr成为C++11正式反对的成分。这就说明我们要避免要去使用它。
3、shared_ptr的声明和定义:
std::shared_ptr<string> p1{ new string(“hello”) };
std::shared_ptr<string> p2 = std::make_shared<string>(“hello”);
上面两种方式都可以,提倡用第二种方式比较快,也比较安全。
4、shared_ptr重置内存:
shared_ptr<string> p1;
p1 = std::make_shared<string>("hello");
p1.reset(new string("world"));
5、定义一个Deleter:
shared_ptr<string> p1 (new string( “hello”), [ ](string* p){
cout << “Delete ” << *p << endl;
delete p;
p = nullptr});
当smart pointer最后一个拥有者被销毁时,会调用这个lambda函数。
Deleter定义的必要性在于shared_ptr提供的default delete人调用的是delete,而不是delete[]。这就意味着如果使用new[]建立一个array of object,你必须定义你自己的deleter。
对于这一点,unique_ptr就不一样了,它大不必如果费劲,它有一个针对array的优化,所以不用自己去定义deleter。
6、weak_ptr的使用解决场景:
(环式指向)。即是两个对象使用shared_ptr互相指向对方。
(reference的指针寿命比所指对象的寿命更长)。导致访问已被释放的数据。
为什么能解决以上的场景呢?因为weak_ptr允许“共享但不拥有”某对象。 下面具体
分析weak_ptr是怎么解决的。
看下面的代码:
分析:
在P1还没被赋值之前,kid对象已经被共享3次并各自拥有(划红线的地方)。就如下图画的一样,在这种情况下,当main()结束时P1也不会被释放,因为他们的计数值都不为0,于是每个Person的析构函数都从未被调用。
用weak_ptr来解决:
分析:
使用weak_ptr之后,mom对象和dad对象都只是共享kid对象,但不拥有。同样在init之后给P1赋值,此时的计数值use_count()只是1。所以就可以避免环式指向导致泄露的问题。但有一点要注意的是,使用weak_ptr时,我们必须稍微改变访问被指对象的方式。不应该再调用:
P1->mother->kids[0]->name
现在必须在式子内加上lock():
P1->mother->kids[0].lock()->name
为什么一定要加上lock()呢?因为Mother对象内的kids保存的是weak_ptr,并不真正拥有对象,一旦外面最末拥有者在你访问的同时释放了对象,那么此时就会产生访问已经析构的对象的错误。加上lock()保证对象的存在。
7、std::enable_shared_from_this<>的使用:
但是要注意的一点是,不能在构造函数内调用shared_from_this()。因为shared_ptr本身被存放于Person的base class,也就是enable_shared_from_this<>的内部的一个private成员中,在Person构造结束之后才能被访问。
8、注意:shared_ptr并非线程安全。因此,当在多个线程中以shared_ptr指向同一个对象,必须使用诸如mutex或lock等技术。
9、注意:C++11规定了编译器在函数return时会自动加上move()。