是否可以删除非新对象?

时间:2010-12-04 19:47:14

标签: c++ memory-management destructor new-operator

我有一个带有指向其他对象的指针向量的对象,如下所示:

class Object {
    ...
    vector<Object*> objlist;
    ...
};

现在,对象将以这两种方式添加到列表中:

Object obj;
obj.objlist.push_back(new Object);

Object name;
Object* anon = &name;
obj.objlist.push_back(anon);

如果是一个简单的构造析构函数

~Object {
    for (int i = 0; i < objlist.size(); i++) {
        delete objlist[i];
        objlist[i] = NULL;
    }
}

在尝试删除未使用new创建的对象时会不会产生任何不良后果?

4 个答案:

答案 0 :(得分:34)

是的,会有不良影响。

您不得delete未使用new分配的对象。如果对象是在堆栈上分配的,则编译器已在其作用域的末尾生成对其析构函数的调用。这意味着您将两次调用析构函数,可能会产生非常糟糕的影响。

除了两次调用析构函数之外,您还将尝试释放从未分配的内存块。 new运算符可能会将对象放在堆上; delete期望在new运算符放置它们的同一区域中找到该对象。但是,未分配new的对象存在于堆栈中。这很可能会使程序崩溃(如果第二次调用析构函数后它还没有崩溃)。

如果堆上的Object比堆栈中的Object长得多,你也会陷入深深的麻烦:你会得到一个悬挂式引用到堆栈的某个地方,你就是'下次访问时会得到不正确的结果/崩溃。

我看到的一般规则是堆栈上的东西可以引用堆上的东西,但堆上的东西不应该引用堆栈上的东西,因为它们很可能会比堆栈对象更长久。两者的指针不应混合在一起。

答案 1 :(得分:5)

不,你只能delete new编辑

Object* anon = &name;

当名称超出范围时,向量中将出现无效指针。

答案 2 :(得分:1)

这不起作用 - 如果delete new未分配delete您违反规则的对象或shared_ptr<>运营商。

如果您需要让您的矢量存储对象可能需要删除,也可能不需要删除,您需要以某种方式跟踪它。一种选择是使用智能指针来跟踪指向的对象是否是动态的。例如,shard_ptr<>允许您在构造{{1}}时指定deallocator对象,并且文档提及:

  

例如,将shared_ptr返回到静态分配的对象时,“no-op”解除分配器很有用

但是,在将指针传递给自动变量时仍应小心 - 如果向量的生命周期长于变量的生命周期,那么它将在某个时刻引用垃圾。

答案 3 :(得分:1)

您实际要问的是,通过new运算符删除未通过delete分配的对象是否安全,如果是,为什么?

不幸的是,这会被代码中的其他一些问题混淆。如上所述,当 name 超出范围时,您最终会得到一个无效指针。

请参阅zneak's answer了解原始问题未导致安全操作的原因,以及为什么 name 的范围确实很重要。