我有一个带有Node的LinkedList,其中包含一个字段:
void* _data;
现在,我想删除这些数据,但我不知道数据是原始的还是动态分配的对象。
所以,如果写:
~Node() {
delete _node;
}
并且数据是一个动态分配的对象,它会调用对象的析构函数还是会有内存泄漏?
那么我怎样才能做到这一点?
答案 0 :(得分:7)
不要那样做!
在delete
上调用void pointer
是未定义行为。 [参考下面]
未定义的行为意味着任何事情都可能发生,程序有时可能崩溃或有时可能会工作,但您无法始终预测其行为,这是一种非常糟糕的编程方式。
正如你用void*
得出的结论,delete
运算符无法确定它需要调用哪个类析构函数,最终会导致未定义的行为。
那我该怎么做呢?
我看到你有一个void*
指针的意图是有一个通用的链接列表实现。为此,C ++已经提供了模板化的通用链接列表 std::list ,您可以使用它,因为重新发明轮子没有意义,而且很可能是标准链接列表实现将优于任何自定义链接列表的自定义实现版本。
如果您仍想拥有自己的链接列表版本。您应该实现一个通用的模板链接列表类,就像 std :: list 那样。
查看 Template Programming 。
<强>参考:强>
根据 C ++ 03标准版5.3.5 / 3:
在第一个备选(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或者行为未定义。在第二种方法(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义(FootNote 73)。
脚注73)
这意味着无法使用void *类型的指针删除对象,因为没有类型为void的对象
答案 1 :(得分:3)
如果您需要此行为,请使用template。你编写的代码无法知道要调用的析构函数。
答案 2 :(得分:2)
当_node
类型为void*
时,delete _node
始终不正确,因为delete
使用的操作数类型必须始终是指向对象动态类型的指针构造,或者作为该类型的基类的类型,提供基类类型具有虚拟析构函数。显然,void*
无法满足该要求的任何一部分。
如果您使用的是void*
,则需要在调用delete
之前找回回到原始类型的内容。一种有效的方法是使用像std::shared_ptr<void>
这样的东西,它可以在构造(或重置)时存储适当的删除器的方式使用,并在节点被销毁时自动调用。
答案 3 :(得分:0)
删除void指针很危险。编译器可能会警告或拒绝您的代码。 C ++标准说你不应该这样做。
实际上,如果编译器确实接受了你的代码,它只会在不调用析构函数的情况下释放内存。