10

可能重复:
删除空指针是否安全?

假设我有一个new分配给一个名为的类MyClass,并且分配很简单:

MyClass *myClassPtr = new MyClass();

我存储对void*我简单地说的列表的引用

myListOfPointers.add(static_cast<void*>(myClassPtr)); // this has to be void*

后来我释放内存而不是这样做:

delete myClassPtr

我用:

delete MyListOfPointer.get(0)

(假设 myClassPtr 引用是零索引。)另外,请注意它必须是void*因为这个列表可以存储不同类型的指针,所以我不知道我要删除的指针类型:

所以我不能做任何事情:

delete static_cast<MyClass*>(MyListOfPointer.get(0))

这种方式会释放正确的内存大小吗?( sizeof(MyClass))?

注意:
我不是在寻找任何指向智能指针的答案。

4

4 回答 4

14

通过 a 删除void*会导致未定义的行为,因此您不会得到任何保证。

5.3.5 删除[expr.delete]

1 delete-expression 运算符销毁由 new-expression 创建的最派生对象 (1.8) 或数组。
[...]
操作数应具有指向对象类型的指针,或具有指向对象类型指针的单个非显式转换函数(12.3.2)的类类型。结果类型为 void。78

78) 这意味着不能使用 void* 类型的指针删除对象,因为 void 不是对象类型。

强调我的。


所以即使你说不说,答案是创建某种形式的智能指针。它需要使用类型擦除在外部隐藏类型(允许异构列表),但在内部跟踪它给出的类型以及如何删除它。很像的东西boost::any

于 2012-10-06T17:15:58.740 回答
2

void指针没有类型信息。如果MyClass有析构函数,它不会被调用。编译器需要知道它正在删除什么,以便生成适当的代码。如果列表中的所有指针都属于同一类型,那么您应该将该类型存储在列表中,而不是作为void. 如果指针是不同的类型,但派生自公共基类型,则为该基类型提供一个虚拟构造函数并存储该类型的指针。

于 2012-10-06T17:31:15.843 回答
1

没有必要使用智能指针,它只是智能的。

话虽如此,还有很多其他的可能性。唯一要做的就是将类型信息存储在实际对象中。

class Holder {
public:
    template <typename T>
    explicit Holder(T const volatile* t):
        _data(static_cast<void const volatile*>(t)),
        _delete(&Delete<T>)
    {}

    void apply() { _deleter(_data); }

private:
    typedef void (*Deleter)(void const volatile*);

    template <typename T>
    static void Delete(void const volatile* p) {
        delete static_cast<T const volatile*>(p);
    }

    void const volatile* _data;
    Deleter _deleter;
};

现在:

std::list<Holder> owningList;

owningList.push_back(Holder(somePointer));

for (Holder& h: owningList) { h.apply(); }
于 2012-10-06T17:37:47.063 回答
0

这个问题的正确答案当然是“不”

编辑:要求提供更多信息,即使我已经在对该问题的评论中做了,删除 void* 是未定义的,这个问题是问这个问题的另一种方式:删除 void 指针是否安全?- 有关详细信息,请参阅那里的答案。

于 2012-10-06T17:20:14.350 回答