智能指针

动机

帮助程序员自动释放申请的动态内存。智能指针也是模板类


shared_ptr

make_shared函数

一般通过次函数创建指向的对象,该函数还返回一个智能指针。注意参数一定要和该类型的某个构造函数一致

这样定义的话我感觉以后可以告别new了。

shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10, '9');

通过类型的调用析构函数销毁 

1.当所指向对象的引用计数为0时,会自动调用指向对象的析构函数进行销毁,这是不是说还得会写析构函数

2.局部对象离开作用域会递减引用计数

shared_ptr<Foo> factory(T arg)
{
    return make_shared<Foo>(arg);
}

情况解析:离开作用域减1。

void use_factory(T arg)
{
    shared_ptr<Foo> p = factory(arg);
} //p离开作用域,递减引用计数,然后为0就会调用指向对象的析构函数。

情况解析:返回给其他对象就加1

void use_factory(T arg)
{
    shared_ptr<Foo> p = factory(arg);
    return p;
} //p离开作用域,递减引用计数,然后为0就会调用指向对象的析构函数。

shared_ptr成员变量

当含有shared_ptr成员的对象销毁时,该成员变量会自动销毁,所以可以用默认析构函数销毁,不用再另外写。


直接管理内存大法 

用法

直接管理内存是指自己用new分配内存,用delete释放内存。

缺陷

1.不能使用默认的拷贝,赋值,析构函数,因为默认的不会帮你分配和释放内存。

2.造成多次delete的问题。

new分配

1.分为默认初始化和值初始化。

int *p1 = new int;   //默认初始化。未定义值
int *p2 = new int();  //值初始化。默认为0

注意:

对于内置基本类型,默认初始化和值初始化结果不同;对于有构造函数的类型,上面两者都会调用默认构造函数。

2.创建const对象

const int *p3 = new const int(1024);   //

3.nothow选项 

如果分配不了内存,常规会抛出异常。

int *p4 = new(nothrow) int(1024);   //

delete释放 

1.必须记着释放分配的动态内存。

Foo * factory(T arg)
{
    return new Foo(arg); //分配内存了
} 

错误的用函数写法

void useFactory(T arg)
{
    Foo *p = factory(arg);
}  //离开函数作用域不会自动释放的

正确的用函数写法

void useFactory(T arg)
{
    Foo *p = factory(arg);
    delete p;   //手动释放
}   


​
void useFactory(T arg)
{
    Foo *p = factory(arg);
    return p;  //以后记着释放
}  

2.置为nullptr 

一般delete后的p为空悬指针,造成指向无效问题,最好指向nullptr。

int *p = new int(42);
auto q =p;
delete p;
p = nullptr;   //q也无效,但是会忘记置为null,也可能再次delete q

shared_ptr和new

1.explicit的构造函数

构造方式变成如下:

shared_ptr<int> p1 = new int(42); //xxx
shared_ptr<int> p2(new int(42));

 也不能向形参传递普通指针

void process(shared_ptr<int> p)
{
}

int *x(new int(1024));
process(x);  //xxx,不支持构造一个临时对象

2. 通过旧式指针初始化另一个智能指针,俩智能指针独立 (重点)

shared_ptr<int> p(new int(42)); 
int *q = p.get();
{
    shared_ptr<int>(q);  //建立临时对象
} //离开作用域销毁临时变量,还会释放指向对象的内存
int foo = *p;  //xxx,内存已被释放

智能指针和异常

1.智能指针确保即使发生异常也能释放内存 

如果被f自己捕获,智能指针会释放吗?

void f()
{
    shared_ptr<int> p1 (new int(42));
    int *p2 = new int(42);  
    //抛出异常了且没被f捕获
    delete p2;   //到不了p2这句,然后就不会释放了
}  

2.智能指针与哑类

哑类指没有析构函数的类,资源不会释放。

connection connect(destination *);  //这里应该是不完全类啊,居然也能用
void disconnect(connection);

void f(destination &d)
{
    connection c = connect(&d);  //xxx,这里说不完全类了
    
}//函数退出不会调用析构释放资源

可以通过智能指针传个删除器

//删除器函数
void end_connection(connection *p)
{
    disconnect(*p);  //xxx,这里说不完全类了
}

void f1(destination &d)
{
    connection c = connect(&d);  //xxx,这里说不完全类了
    shared_ptr<connection> p(&c, end_connection);
    
}

 


unique_ptr

特性

独占对象

构造方式

只能通过new绑定了

unique_ptr<double> p1;
unique_ptr<int> p2(new int(42));

无拷贝和赋值操作

由于独占,所以拷贝和赋值也没必要支持 

unique_ptr<int> p2(new int(42));

unique_ptr<int> p3(p2);  //xxx,直接报错,定义为delete
p3 = p2; //xxx,运行才报错,也是delete的

release和reset区别 

u.release(); //只是切断联系,不会释放内存

u.reset();  //会释放内存

可以拷贝将要销毁的unique_ptr

此规则允许我们返回一个unique_ptr局部对象。

unique_ptr<int> clone(int p)
{
    return unique_ptr<int>(new int(p));
}

weak_ptr

特性

拥有对象但不更改引用计数,也不负责释放对象

构造方式

通过shared_ptr构造,是它的小弟

auto p = make_shared<int>(42);
    
weak_ptr<int> wp(p);

检查指向对象是否有效

一般通过lock()函数取得shared_ptr,然后判断是否为空

if(shared_ptr<int> np = wp.lock())
    {
        
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值