C++中智能指针最常用的shared_ptr和unique_ptr

目录
  • shared_ptr
    • 使用shared_ptr注意
  • unique_ptr

shared_ptr

基本用法: 可以通过构造函数, make_shared<T>辅助函数和reset()方法来初始化shared_ptr

1. 初始化方法

    shared_ptr<int> p1(new int(1));
    shared_ptr<int> p2 = p1;
    shared_ptr<int> p3;
    p3.reset(new int(1));
    shared_ptr<int> p4 = make_shared<int>(int(5));

优先使用make_shared来构造, 更加高效

不能用一个原始指针直接赋值智能指针, 以下方式是错误的

shared_ptr<int> p5=new int(1); //error

2.获取智能指针的原始指针: 通过get方法

    shared_ptr<int> ptr = make_shared<int>(int(5));
    int *p=ptr.get();

3.指定删除器:自定义指针销毁方式

void ptr_deleter(const int*p)
{
    delete p;
}
shared_ptr<int> p(new int, ptr_deleter);

第二个参数指定删除器(一个可调用对象, 其中参数为该类型的指针, 如上面为int*)

当shared_ptr引用计数为0时, 调用传入的而不是默认的删除器来释放对象的内存

当用shared_ptr管理动态数组时, 需要指定删除器, 因为shared_ptr默认删除器不支持数组对象

如下使用lambda表达式作为删除器

shared_ptr<int> p(new int[10],[](int*p){delete []p;});

通过default_delete作为删除器, 同时封装一个make_shared_array函数来支持数组

template<typename T>
shared_ptr<T> make_shared_array(int size)
{
    return shared_ptr<T>(new T[size],default_delete<T[]>());
}

(自测)貌似这样也支持数组

shared_ptr<int[]> ptr(new int[10]);

使用shared_ptr注意

(1)不要用一个原始指针初始化多个shared_ptr

    int *ptr = new int;
    shared_ptr<int> p1(ptr);
    shared_ptr<int> p2(ptr);  //错误

(2)不要在函数实参中创建shared_ptr

function(shared_ptr<int>(new int),g());

参数的计算顺序可能没有固定顺序, 若是new int后执行g()抛出异常, 则shared_ptr还没有创建, 则new int内存泄漏了

(3)不要用this指针构造shared_ptr作为返回值

class A
{
public:
    shared_ptr<A> get_self()
    {
        return shared_ptr<A>(this);
    }
    ~A()
    {
        cout << ("destructor") << endl;
    }
};
int main()
{
    shared_ptr<A> p1(new A);
    shared_ptr<A> p2 = p1->get_self();
    return 0;
}

destructor

destructor

以上代码p1和p2相当于同一个new A初始化, 会shared_ptr销毁时, 会重复析构

正确做法:

让该类继承enable_shared_from_this<>, 同时调用shared_from_this()返回

class A :public enable_shared_from_this<A>    //继承
{
public:
    shared_ptr<A> get_self()
    {
        return shared_from_this();            //调用该函数
    }
    ~A()
    {
        cout << ("destructor") << endl;
    }
};
int main()
{
    shared_ptr<A> p1(new A);
    shared_ptr<A> p2 = p1->get_self();
    return 0;
}

destructor

只要用shared_ptr, 调用的成员函数里都不能使用this构造, 否则都会出错

class A
{
public:
    void test()
    {
        shared_ptr<A>(this); //错误
    }
    ~A()
    {
        cout<<(  "destructor"  )<<endl;
    }
};
shared_ptr<A> p(new A);
p->test()

另外, 不要在构造函数里使用shared_from_this

(4)避免循环引用

以下代码会由于循环引用, 引用计数值都为1, 导致两个指针都不会析构

class A;
class B;
class A
{
public:
    shared_ptr<B> b_ptr;
    ~A()
    {
        cout << ("A destructor") << endl;
    }
};
class B
{
public:
    shared_ptr<A> a_ptr;
    ~B()
    {
        cout << ("B destructor") << endl;
    }
};
int main()
{
    shared_ptr<A> a_p(new A);
    shared_ptr<B> b_p(new B);
    a_p->b_ptr=b_p;
    b_p->a_ptr=a_p;
}

//没有输出

unique_ptr

unique_ptr不允许复制, 不允许其他的智能指针共享其内部的指针, 但可以转移

    unique_ptr<int> ptr(new int);
   // unique_ptr<int> ptr2=ptr;    error 不可以赋值
    unique_ptr<int> ptr3=move(ptr); //用move进行转移
    assert(ptr!=nullptr); //转移后ptr为nullptr

自定义make_unique函数且让其支持定长数组

思路

不是数组, 返回unique_ptr<T>

是数组且非定长数组, 返回unique_ptr<T>, 即不应该调用make_unique<T[10]>(10)而是make_unique<T[]>(10)

最后过滤掉该定长数组(函数声明为delete)

// !is_array_v确定不是数组, 返回unique_ptr<T>
template<typename T,typename ...Args>
enable_if_t<!is_array_v<T>,unique_ptr<T>> make_unique_(Args&&...args)
{
    return unique_ptr<T>( new T(forward<Args>(args)...));
}
//定长数组如T[10],  不应该调用make_unique<T[10]>(10);而是make_unique<T[]>(10);
// is_array_v确定是数组且!extent_v<T>确定非定长数组, 返回unique_ptr<T>
template<typename T,typename ...Args>
enable_if_t<is_array_v<T>&&!extent_v<T>,unique_ptr<T>> make_unique_(size_t size)
{
    using U=remove_extent_t<T>;
    return unique_ptr<T>( new U[size]);
}
//否之过滤掉该定长数组
template<typename T,typename ...Args>
enable_if_t<extent_v<T>,void> make_unique_(Args&&...)=delete;
    unique_ptr<int> ptr= make_unique_<int>(10);
    unique_ptr<int[]> ptr1= make_unique_<int[]>(10);

不过unique_ptr本身也支持数组, shared_ptr自测也支持, 如下

    unique_ptr<A[]> ptr1(new A[10]);
    shared_ptr<A[]> ptr2(new A[10]);

unique_ptr也支持删除器, 但和shared_ptr有区别, 要指定删除器类型

    shared_ptr<A> p1(new A[10],[](A*p){delete []p;});
   // unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 错误
    unique_ptr<A,void(*)(A*)> p2(new A[10],[](A*p){delete []p;}); //正确

如果希望lambda删除器捕获变量, 则需要用function包装

    unique_ptr<A,void(*)(A*)> p1(new A[10],[&](A*p){delete []p;});       //错误
    unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正确

到此这篇关于C++中智能指针最常用的shared_ptr和unique_ptr的文章就介绍到这了,更多相关C++ shared_ptr和unique_ptr内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 关于C++智能指针shared_ptr和unique_ptr能否互转问题

    C++中的智能指针最常用的是shared_ptr和unique_ptr,C++新手最常问的问题是我从一个函数中拿到unique_ptr,但要转成shared_ptr才能使用,要怎么转换?同理是否能将shared_ptr转换成unique_ptr? 我们先简单看看shared_ptr是什么. std::shared_ptr<Widget> a = std::make_shared<Widget>(); 这句代码会在栈中创建一个shared_ptr对象,其最基本的2个指针,一个指向在堆

  • C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)

    shared_ptr基本用法 shared_ptr采用引用计数的方式管理所指向的对象.当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1.当shared_ptr离开作用域时,引用计数减1.当引用计数为0时,释放所管理的内存. 这样做的好处在于解放了程序员手动释放内存的压力.之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存:现在这一过程就可以交给shared_ptr去做了. 一般我们使用make_shared来

  • C++中智能指针最常用的shared_ptr和unique_ptr

    目录 shared_ptr 使用shared_ptr注意 unique_ptr shared_ptr 基本用法: 可以通过构造函数, make_shared<T>辅助函数和reset()方法来初始化shared_ptr 1. 初始化方法 shared_ptr<int> p1(new int(1)); shared_ptr<int> p2 = p1; shared_ptr<int> p3; p3.reset(new int(1)); shared_ptr<

  • C++中智能指针如何设计和使用

    智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference count).智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针.每次创建类的新对象时,初始化指针并将引用计数置为1:当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数:对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果

  • 一文掌握 C++ 智能指针的使用方法

    目录 一.RAII 与引用计数 二.std::shared_ptr 三.std::unique_ptr 四.std::weak_ptr 五.总结 一.RAII 与引用计数 了解 Objective-C/Swift 的程序员应该知道引用计数的概念.引用计数这种计数是为了防止内存泄露而产生的. 基本想法是对于动态分配的对象,进行引用计数,每当增加一次对同一个对象的引用,那么引用对象的引用计数就会增加一次, 每删除一次引用,引用计数就会减一,当一个对象的引用计数减为零时,就自动删除指向的堆内存. 在传

  • C++ 中boost::share_ptr智能指针的使用方法

    C++ 中boost::share_ptr智能指针的使用方法 最近项目中使用boost库的智能指针,感觉智能指针还是蛮强大的,在此贴出自己学习过程中编写的测试代码,以供其他想了解boost智能指针的朋友参考,有讲得不正确之处欢迎指出讨论.当然,使用boost智能指针首先要编译boost库,具体方法可以网上查询,在此不再赘述. 智能指针能够使C++的开发简单化,主要是它能够自动管理内存的释放,而且能够做更多的事情,即使用智能指针,则可以再代码中new了之后不用delete,智能指针自己会帮助你管理

  • C++中auto_ptr智能指针的用法详解

    智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足以涵盖auto_ptr的大部分内容. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有

  • C++智能指针之shared_ptr的具体使用

    目录 std::shared_ptr概念 shared_ptr模板类 shared_ptr的构造和析构 shared_ptr赋值 make_shared 计数线程安全? enable_shared_from_this shared_ptr使用注意事项: 总结 std::shared_ptr概念 unique_ptr因为其局限性(独享所有权),一般很少用于多线程操作.在多线程操作的时候,既可以共享资源,又可以自动释放资源,这就引入了shared_ptr. shared_ptr为了支持跨线程访问,其

  • 一文掌握C++ 智能指针全部用法

    目录 一.为什么要使用智能指针 二.auto_ptr 三.unique_ptr 四.shared_ptr 五.weak_ptr 六.智能指针的使用陷阱 七.总结 为什么要学习智能指针? 咳咳,这个问题不是问大家的,是询问我自己的! 我依稀记得刚离校出来找实习工作那会,去面试一份工作,其中有一个环节需要答题:有一道题目就是问什么是智能指针?卧槽?当时我就懵逼,智能指针我压根就没有听说过- 最后,面试的这份工作理所应当的黄了. 差不多是一年前左右吧,现在趁有闲余时间,学习一下智能指针,丰富一下自己!

  • C++11智能指针之weak_ptr详解

    如题,我们今天要讲的是 C++11 引入的三种智能指针中的:weak_ptr. 在学习 weak_ptr 之前最好对 shared_ptr 有所了解.如果你还不知道 shared_ptr 是何物,可以看看另一篇文章: [C++11新特性] C++11智能指针之shared_ptr 1.为什么需要weak_ptr? 在正式介绍weak_ptr之前,我们先来回忆一下shared_ptr的一些知识. 我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对

  • C++11 智能指针的具体使用

    目录 智能指针的原理 RAII 智能指针的原理 auto_ptr 1.auto_ptr的使用及问题 unique_ptr shared_ptr shared_ptr的循环引用 智能指针的原理 RAII RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存.文件句柄.网络连接.互斥量等等)的简单技术. 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源. 借此,我

随机推荐