C++ primer 薄片系列之 智能指针

shared_ptr

引用次数和交换操作

    std::shared_ptr<A> a(new A);
    std::cout << a.use_count() << std::endl; //  输出 1
    std::shared_ptr<A> b;
    std::cout <<  b.use_count() << std::endl; //  输出 0
    a.swap(b);
    std::cout << a.use_count() << std::endl; //  输出 0
    std::cout <<  b.use_count() << std::endl;//  输出 1

reset 相关操作

    std::shared_ptr<int> b(new int);
    b.reset() //reset释放对象
    b.reset(new int) //b 指向新的对象

    b.reset(q,d)//调用d 而不是delete 去释放q
    std::shared_ptr<A> a(new A);
    a.reset(new A, [](A*){
   
   std::cout << "I do nothing" << std::endl;});//  使用新的lambda表达式而不是delete去释放,这里a的reset后的新对象,并没有释放

unique_ptr

它的reset 没有shared_ptr中的reset(p,d)操作, 即不能在reset 函数中传递删除器,只能在实例化模板时提供删除器

    std::shared_ptr<A> a;
    if(!a)
    {
        std::cout << "a is empty" << std::endl;
    }
    std::unique_ptr<A> b(new A);
    a.reset(b.release());// b放弃对指针的控制权,返回指针给 a.reset做参数,b置空
    if(!b)
    {
        std::cout << "b is empty" << std::endl;
    }

    std::unique_ptr<A> b(new A);
    b.reset(nullptr);//OR b.reset() 均可使b置空
    if(!b)
    {
        std::cout << "b is empty" << std::endl;
    }

    std::unique_ptr<A> b(new A, [](A*){
   
   std::cout << "我代替了delete操作" << std::endl;}); // 错误, unique_ptr reset没有重载这个函数
    std::unique_ptr<A,void(*)(A*)> s(new A, [](A*){
   
   std::cout << "I do nothing" << std::endl;});// 只能在unique_ptr实例化的时候,提供模板参数,这里采用了lambda表达式。也可以使用函数
    void delFunc(A *)
    {
        std::cout << "I do nothing" << std::endl;
    }
    std::unique_ptr<A,decltype(delFunc)*> s2(new A,delFunc);

—管理动态数组

 unique_ptr<A[]>  up(new A[]);
 up在作用域结束后,会自动调用delete[] ,释放动态数组。
 访问动态数组中的元素时,可以直接 up[i]  的形式

 shared_ptr则必须制定动态数组删除器
 shared_ptr< A > sh(new A[10]); //严重bug
 std::shared_ptr< A> sp(new A[10],[](A *p){
   
   delete[] p;});//必须定义删除器
 访问动态数组的元素时,只能以 *(sh.get()+i)的方式获取 sh内置动态数组中的元素

weak_ptr

w.use_count()
w.expired() use_count == 0 时为true,否则false
w.lock() expired 为true时返回空shared_ptr否则返回指向w的对象的shared_ptr
避免循环引用

class B;
class A
{
public:
    shared_ptr<B> pb;
};
class B
{
public:
    shared_ptr<A> pa;
};
{
    shared_ptr<A> a(new A);
    shared_ptr<B> b(new B);
    a->pb = b;//b.use_count() == 2
    b->pa = a;//a.use_count() == 2
}
a和b离开作用域, 释放B,导致b的引用次数除掉1,此时b所指的内存引用次数为2-1 = 1,同样a所指向的内存的引用次数也是2-1 = 1,从 a和b所指向的内存不能析构,形成了内存泄露。
此时需要把 pa换成 weak_ptr<A>, pb 换成 weak_ptr<B>, OK了。

Allocator

这玩意存在的理由在于, new的负担太重了,它完成了内存分配和对象构造两件事情。为了分离这两件事情,所以就有了它。

   class A
   {
       A(){}
       ~A(){}

   };
   std::allocator<A> alloc;
   auto p = alloc.allocate(10); // 此时A的构造函数不会被调用
   auto q = p;
   alloc.construct(q++);
   while (q != p)
   {
       alloc.destroy(--q);
   }
   alloc.deallocate(p, 10);


   std::allocator<A> alloc;
   auto p = alloc.allocate(10);
   拷贝和填充未初始化内存的算法
   std::uninitialized_copy(s.begin(),s.end(), p); // 调用A的拷贝构造函数
   std::uninitialized_copy_n(s.begin(), 2, p); // 拷贝构造2A 到p
   A data;
   std::uninitialized_fill(p,p+2, data);//填充data的拷贝到原始内存
   std::uninitialized_fill_n(p,2, data);

猜你喜欢

转载自blog.csdn.net/jxhaha/article/details/78424674