C++ Primer第十二章③

C++ Primer

更多内容戳这里

动态内存

shared_ptr和new结合使用

这个标题是我们的目标,同时我们也要想,为什么要结合着使用。在此之前,先看些基础知识。

智能指针的构造函数是explicit的

可能你已经忘了explicit是什么意思了,我回去翻了下,是禁止隐式转换的意思,就因为这个规定,接下来就有一些事情可以搞了:

shared_ptr p1(new int(24)); //我们知道这样是对的,直接初始化
shared_ptr p2 = new int(24); //那这样呢?错了

第二个为什么错了呢?因为等号右边用new构造临时对象时返回的是一个普通指针int*,它试图隐式转换为智能指针,但是我们的智能指针的构造函数很无情,不允许隐式转换,所以报错了。 再来个函数返回类型的例子:

shared_ptr clone(int p)
{
    return new int(p); //错误:试图隐式转换为shared_ptr
}
//正确示例
shared_ptr clone(int p)
{
    return shared_ptr( new int(p) );
}

默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存(就是说它得指向new出来的),因为智能指针会delete啊。我们当然也可以让智能指针指向其他类型的资源,但是你得提供自己的释放操作去代替delete。(以后再介绍怎么定义自己的释放操作。)

下面两个图看表格就行

不要混合使用普通指针和智能指针

来个错误例子:

void process(shared_ptr ptr){}
int *x(new int(24));
process(shared_ptr(x));
int j = *x; //x是空悬指针,自己想想为啥,这段代码很重要啊,好好看看

也不要使用get初始化另一个智能指针或为智能指针赋值

还是来一个会导致空悬指针的示例:

shared_ptr p(new int(42));
int *q = p.get();
{
    shared_ptr(q); //两个独立的智能指针指向相同的内存块(要出事情)
} //q指向的内存被销毁
int foo = *p; //p是空悬指针,报错。

其他shared_ptr操作

shared_ptr p(new int(42));
p = new int(1024); //错误:禁止隐式转换
p.reset(new int (1024)); //这样可以,p指向一个新对象
//有时为了避免p原来的内存被释放,我们还会这么写
if(!p.unique()){ p.reset(new string (*p)); }

智能指针和异常

使用智能指针的好处:即便代码出现没有catch到的异常,还是能保证内存的释放:

void f()
{
    shared_ptr sp(new int(42));
    //假设之后的代码出现了没有捕捉到的异常
} //在函数结束时,shared_ptr还是会自动释放内存
//假设代码中还有局部变量来拷贝sp呢,还是会正确释放,除非有函数外部的变量拷贝了sp,想想这是为啥

普通指针来管理动态内存的坏处:

void f()
{
    int* p = new int(42);
    //假设之后的代码出现了没有捕捉到的异常
    delete ip;
}
//虽然代码很好地写了delete ip,但出现异常之后p指向的内存就不会被释放了,根本无法释放

一些没有定义析构函数的类也会出现类似问题:

void f()
{
    connect c; //默认初始化
} //如果没有显示销毁c,那c就不会被销毁了

我们如何改进呢,用智能指针管理,并且定义一个函数(删除器)用来代替delete函数:

void end_connect(connect *p){ disconnetc(*p); } //定义了删除器(调用了一个函数)
void f()
{
    connect c;
    shared_ptr p(&c, end_connect); //用p来管理c的内存
}//退出后c就会被正确关闭销毁
全部评论
请问下这个process函数是什么啊? process(shared_ptr(x)); int j = *x; //x是空悬指针,自己想想为啥,这段代码很重要啊,好好看看
点赞 回复 分享
发布于 2016-12-27 21:30
加油,鼓劲...
点赞 回复 分享
发布于 2016-12-28 10:15

相关推荐

4 收藏 评论
分享
牛客网
牛客企业服务