7

我有一个关于在 C++ 中释放内存的问题:

typedef struct type1
{
   int a;
   int b;
   float c;
} Type1;

typedef struct type2
{
   int a;
   int b;
} Type2;

void *p = new Type1;

delete (Type2 *)p;

p在这种情况下,即使p被转换为不同大小的类型,所指向的内存区域也会被完全删除吗?

4

3 回答 3

14

行为未定义。在这种情况下,动态分配的对象只能通过类型指针删除Type1

首先,通过(Type2 *)pdelete表达式中使用通过获得的指针,您违反了别名规则。p存在一组有限的类型,通过这些类型可以使用指向的对象。C++03 的规则可以在另一个问题的答案中找到。C++11 规则类似(差异与您问题的答案无关)。

即使程序没有违反严格的别名规则,它也会违反delete表达式的要求。规范声明(C++11 §5.3.5[expr.delete]/3):

如果待删除对象的静态类型与其动态类型不同,则静态类型应为待删除对象动态类型的基类,且静态类型应具有虚析构函数或行为未定义。

在您的delete表达式中,对象的静态类型是Type2,而动态类型是Type1。类型不同,但静态类型不是动态类型的基类。

于 2013-01-02T21:33:03.053 回答
4

这将是一个非常糟糕的主意,因为您会要求编译器安排在 Type1 指针上运行 Type2::~Type2 ,并且该析构函数可能会引用对象的末尾。

在传统环境中,最终释放内存是可以的,因为operator delete调用free不关心您在编译时调用的类型。然而,在不那么传统的环境中,这可能是一场灾难。

于 2013-01-02T21:34:19.803 回答
0

尽管詹姆斯已经完美地回答了这个问题,但我想指出一件事:

在正确的 C++ 代码中,您几乎永远不会使用void指针,这意味着您的代码可能看起来像这样:

SubType *p = new SubType;
BaseType* pB = (BaseType*)p;
delete pB;

在这种情况下,即使BaseType有适当的虚拟构造函数,如果SubType不是从BaseType. 常见的 C 风格转换在这里不是很幸运的选择。

但是如果您使用dynamic_cast,编译器很可能不会让您这样做,以防它p不指向多态类型的对象。即使它p指向多态类型的对象,但BaseType不是 的基类型SubTypedynamic_cast也会返回NULL并且您可以适当地处理此状态:

SubType *p = new SubType;
BaseType* safePtr = dynamic_cast<BaseType *>(p);
if (!safePtr) // p doesn't point to object of type derived from BaseType
    ...       // handle this situation
else          // p points to object of polymorphic type derived from BaseType
    delete safePtr;
于 2013-01-02T22:24:03.320 回答