我有一个带有指向其他对象的指针向量的对象,如下所示:
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创建的对象时会不会产生任何不良后果?
答案 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 的范围确实很重要。