12.1动态内存与智能指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了12.1动态内存与智能指针相关的知识,希望对你有一定的参考价值。

1.shared_ptr<>:允许多个指针指向同一个对象
初始化方式:
    shared_ptr<int> p1 = make_shared<int>(10);//最好使用这种方式
    shared_ptr<int> p2(new int(20));        //只能用直接初始化方式

和普通指针有一样的操作,*,->,swap等
支持拷贝与赋值与自定义删除器,特别地:
    p.get()能返回p中保存的指针,如果指针指针释放了其对象,返回指针所指的对象也就消失了。
    p.use_count()返回与p共享的只能指针数量,比较慢,主要用来调试。
    p.unique()若p.use_count()为1,返回true,否则返回false。

shared_ptr会自动销毁所管理的对象并且会自动释放相关联的内存。
原因是因为内存采用了:引用计数。
当计数为0就会自动释放。
    p1 = p2;    //p2引用计数加1,p1引用计数减1

不能将一个内置指针隐式转化为指针指针
shared_ptr<int> f(int p)
{
    return shared_ptr<int>(new int(p));//不能直接放回new int(p)
}

shared_ptr<T> p(q);    //p管理内置指针q所指的对象,q必须指向new分配的内存,且能够转换为T*类型
shared_ptr<T> p(u);    //p从unique_ptr u接管对象的所有权,将u置为空
shared_ptr<T> p(q, d); //q为内置指针,d为可调用对象作为删除器
shared_ptr<T> p(p2, d);//p是shared_ptr2的拷贝,p使用对象d作为删除器
p.reset();             //释放p,将p置为空
p.reset(q);            //p会指向q
p.reset(q, d);         //调用删除器d

shared_ptr不支持管理动态数组,当初始化动态数组时必须定义自己的删除器:
    shared_ptr<int> p(new int[10], [](int *n){ delete[]n; });//必须要自定义删除器
因此访问数组中的元素操作也会不同:
    for(int i = 0; i < 10; ++i)
    {
        *(p.get() + i) = u(e);//只能通过get()来访问
    }
注意:不要用get初始化另一个智能指针或者为另一个智能指针赋值

2.unique_ptr<>:独占所指向的对象,也就是同一时刻只能有一个unique_ptr指向一个给定的对象
初始化形式:
    unique_ptr<int> p(new int(10));    //只能直接初始化
不支持拷贝与赋值
支持自定义删除器,和普通指针也有*,->,swap等,也有get()函数
unique_ptr<T> u1;    //指向类型为T的对象,会使用delete
unique_ptr<T, D> u2; //会使用删除器D来释放
unique_ptr<T, D> u(d);//空unique_ptr,使用d来代替delete
u = nullptr;         //释放u所指的对象,将u置为空
u.release();         //u放弃对指针的控制权,返回指针,将u置为空
u.reset();           //释放u所指的对象
u.reset(q);          //如果提供内置指针q,令u指向这个对象
u.reset(nullptr);

unique_ptr能够管理动态数组:
    unique_ptr<int[]> a;
    unique_ptr<int[]> a(new int[10]);    //注意类型
     能够使用u[i]访问数组
其他操作和普通一样

3.weak_ptr<>:不控制所指向对象生存期的只能指针,指向由一个shared_ptr管理的对象
初始化形式:
    weak_ptr<int> w;        //p必须为shared_ptr
    weak_ptr<int> w = p;
    weak_ptr<int> w(p);
    w = p;
    w.reset()        //将w置为空
    w.use_count();   //与w共享对象的shared_ptr数量
    w.expired();     //若w.use_count()为0,返回true,否则返回false
    w.lock();    //如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr
注意:由于对象可能不存在,不能直接访问对象,需要使用lock

weak_ptr有一个非常有用的地方在于,破除shared_ptr的循环引用:
class A
{
public:
    A(int a) : i(a) {}
    ...
public:
    int i;
    shared_ptr<int> p;
};

int main()
{
    shared_ptr<A> one = make_shared<A>(1);
    shared_ptr<A> two = make_shared<A>(2);
    one->p = two;
    two->p = one;
    return 0;
}
这种情况造成了循环引用,作用域结束时one和two都不会被释放,正确的做法是将one和two其中一个变为weak_ptr

class A;
class B;
class A
{
private:
    shared_ptr<B> p;
};
class B
{
private:
    shared_ptr<A> p;
};
这种情况也造成了循环引用,应该讲其中一个变为weak_ptr

 

以上是关于12.1动态内存与智能指针的主要内容,如果未能解决你的问题,请参考以下文章

动态内存与智能指针

动态内存与智能指针

动态内存与智能指针

《C++Primer(第5版)》第十二章笔记

第十二章 动态内存与智能指针

动态内存——动态内存与智能指针