目录
2.3 通过share_from_this()返回this指针。
C++ 11提供了3种智能指针:std::shared_ptr、std::unique_ptr和std::weak_ptr,使用时需要引用头文件
std::shared_ptr使用引用计数,每一个std::shared_ptr的拷贝都指向相同的内存。在最后一个std::shared_ptr析构事,内存在会被释放。
可以通过构造函数、std::make_shared
- std::shared_ptr<int> p(new int(1));
- std::shared_ptr<int> p2=p;
- std::shared_ptr<int> ptr;
- ptr.reset(new int(1));
- if(ptr){
- cout << "ptr is not null";
- }
我们应该优先使用make_shared来构造智能指针,因为它更加高效。
不能将一个原始指针直接赋值给一个智能指针,例如,下面的这种方法是错误的:
std::shared_ptr
可以看到指针指针的用法和普通指针的用法类似,只不过不需要自己管理分配的内存。std::shared_ptr不能通过直接将原始指针赋值来初始化,需要通过构造函数和辅助方法来初始化。对于一个未初始化的智能指针,可以通过reset方法来初始化,当指针指针中有值的时候,调用reset会使引用计数减1,另外,智能指针可以通过重载bool类型操作符来判断智能指针中是否为空。
当需要获取原始指针事,可以通过get方法来返回原始指针,代码如下:
- std::shared_ptr<int> ptr(new int(1));
- int *p2 = ptr.get();
智能指针初始化可以指定删除器,代码如下:
void DeleteIntPtr(int *p)
{
delete p;
}
std::shared_ptr
当p的引用计数为0时,自动调用删除器DeleteIntPtr来释放对象的内内存。删除器可以是一个lambda表达式,因此,上面的写法还可以为:
std::shared_ptr<int> p(new int,[](int p*){delete p;});
当我们用std::shared_ptr管理动态数组时,需要指定删除器,因为std::shared_ptr的默认删除不支持数组对象,代码如下:
std::shared_ptr<int> p(new int[10]),std::default_delete<int []>);
另外,还可以通过封装一个make_shared_array方法来让std::shared_ptr支持数组,代码如下:
- template<typename T>
- shared_ptr
make_shared_array(size_t size) - {
- return shared_ptr
(new T[size],default_delete()); - }
测试代码
- std::shared_ptr<int> p = make_shared_array<int>(10);
- std::shared_ptr<char> p = make_shared_array<char>(10);
-
智能指针虽然自动管理堆内存,但是他还是有不善陷阱,在使用时需要注意。
例如下面就是错误的:
- int *ptr = new int;
- std::shared_ptr<int> p1(ptr);
- std::shared_ptr<int> p2(ptr); // logic err
下面为错误例子
function (shared_ptr<int> (new int) ,get());
因为C++函数参数的计算顺序在不同的编译器不同的调用约定下可能是不一样的,一般是从右到左,但也有可能是从左到右,所以可能的过程是先new int,然后调用,如果恰好g()发生异常,而share_ptr
- share_ptr
p(new int()) ; - f(p,g());
不要将this指针作为share_ptr返回出来,因为this指针本质上市一个裸指针,因此,这样可能会导致重复析构,看下面例子。
- struct A{
-
- shared_ptr GetSelf(){
- }
- };
-
- int main(){
- shared_ptr sp1(new A);
- shared_ptr sp2 = sp->GetSelf();
- return 0;
- }
正确写法,正确返回this的shared_ptr的做法是:让目标类通过派生std::endable_shared_from_this
- {
- std::shared_ptr GetSelf(){
- return shared_from_this();
- }
- };
-
- std::shared_ptr spy(new A);
- std::shared_ptr p = spy->GetSelf();
稚嫩指针最大的一个陷阱是循环引用,循环引用会导致内存泄露。
下面是一个经典的循环引用的场景。
测试结果是两个指针A和B都不会被删除,存在内存泄露。循环引用导致ap和bp的引用计数为2,在离开作用域后,ap和bp的引用计数减少为1,并不会减为0,导致两个指针不会被析构,产生内存泄露。解决办法是把A和B任何一成员变量改为weak_ptr.