首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果我删除智能指针正在管理的指针怎么办?

如果我删除智能指针正在管理的指针怎么办?
EN

Stack Overflow用户
提问于 2015-05-18 03:20:42
回答 1查看 1K关注 0票数 2

我从C++初级5版阅读了智能指针。在第12.1.3节中,一些描述如下

智能指针类型定义一个名为“get”的函数,该函数返回到智能指针正在管理的对象的内置指针。该函数适用于需要将内置指针传递给不能使用智能指针的代码的情况。使用'get‘返回的代码不能’删除‘该指针.

下面还给出了一个例子

代码语言:javascript
复制
shared_ptr<int> p(new int(42));       // reference count is 1
int *q = p.get();
{//new block
//undefined:two independent shared_ptr point to the same memory
      shared_ptr<int>(q);
}//block ends, q is destroyed ,and the memory to which q points is freed
int foo = *q; //undefined; the memory to which p points was freed

我能清楚地理解上面的解释。但是,当我遇到练习12.13时,我有点困惑。

代码语言:javascript
复制
#include<iostream>
#include<memory>
using namespace std;

int main(){
        auto sp = make_shared<int>();
        auto p = sp.get();
        delete p;
        cout <<"Before main function exits!"<<endl;  //which I add for debug
        return 0;
}

编译没有错误。但是当运行时出现如下错误

代码语言:javascript
复制
***Error in './ex12_13': double free or corruption(out): 0x09b97018***

和主函数退出前调试的上下文!还没有被执行,这意味着在删除操作之后就会发生错误。我也使用'gdb‘来调试这个程序,在删除之后就会弹出错误。

那么,如何解释错误呢?删除已经释放了内存,但是第二个空闲是什么时候发生的呢?在主功能退出之前?

我将sp的初始化从make_shared函数更改为new,并使用自己的删除器函数代替delete。

代码语言:javascript
复制
        #include<iostream>
        #include<memory>
        using namespace std;
        int main(){
        auto deleter = [](int*p){
             cout<<"deleter called"<<endl; delete p;
        };
        shared_ptr<int> sp(new int, deleter);
        auto p = sp.get();
        delete p;
        cout <<"Before main function exits!"<<endl;  //which I add for debug
        return 0;
}

那么输出结果是

代码语言:javascript
复制
Before main function exits!
deleter called
***Error in './ex12_13_2': double free or corruption(out): 0x08995998***

当程序超出主范围时,局部变量shared_ptr p将被销毁,内存p点将被删除。

这就是为什么“前置函数退出!”首先显示,删除者调用显示后,最后是双空闲错误。

因此,我认为我上面提出的混淆主要是来自于 make_shared。@Ben给出了详细的解释。

您正在删除一个不是来自新的指针,所以您有未定义的行为(任何事情都可能发生)。

但其根本原因可能只能从make_shared的实现中找到。

EN

回答 1

Stack Overflow用户

发布于 2015-05-18 03:24:01

什么时候第二个空闲发生在主函数退出之前?

实际上,它没有。现在,您的程序完全有可能在delete p;上崩溃,但是并不是因为一个双免费。您正在删除一个不是来自new的指针,因此您有未定义的行为(任何事情都可能发生)。特别是,通过将元数据(带有引用计数和删除)和对象放在单个分配中,make_shared常常被优化为最小化分配。可以使用new[]进行分配,或者结果对象指针可能位于分配的中间,而不是开始。在这两种情况下,尝试直接释放delete对象(即使释放智能指针以避免未来的第二次释放)只会带来麻烦。

但是,我们不能确定它到底在哪里崩溃,因为您的测试代码有一个小缺陷。

代码语言:javascript
复制
cout <<"Before main function exits!"<<endl;

不立即显示文本,它只是将其添加到stdout缓冲区。由于程序崩溃,缓冲区实际上从未写入相关的文件描述符。

对于"printf调试“,始终使用非缓冲流(如cerr )。

代码语言:javascript
复制
cerr << "Before main function exits!" << endl;

然后你将看到事件的真正顺序。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30294604

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档