从不同类型的指针释放内存是否安全
Is this safe to deallocate memory from a pointer of a different type than when it was allocated?
我有一个关于在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
指向的内存区域是否会被完全删除?
行为未定义。在这种情况下,可以仅通过类型为Type1
的指针来删除动态分配的对象。
首先,在delete
表达式中使用(Type2 *)p
获得的指针违反了别名规则。存在一组有限的类型,通过这些类型可以使用p
所指向的对象。C++03中的规则可以在另一个问题的答案中找到。C++11规则是相似的(差异与问题的答案无关(。
即使程序没有违反严格的别名规则,它也会违反delete
表达式的要求。规范规定(C++11§5.3.5[expr.delete]/3(:
如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除对象的动态类型的基类,并且静态类型应具有虚拟析构函数,或者行为未定义。
在delete
表达式中,对象的静态类型为Type2
,而动态类型为Type1
。类型不同,但静态类型不是动态类型的基类。
这将是一个非常糟糕的主意,因为你会要求编译器安排在Type1指针上运行Type2::~Type2,而析构函数可能会引用对象的末尾。
在传统环境中,内存的最终释放是可以的,因为operator delete
调用free
,而不关心您在编译时调用它的类型。然而,在一个不那么传统的环境中,这可能是一场灾难。
虽然James已经完美地回答了这个问题,但我想指出一件事:
在正确的C++代码中,你几乎永远不会使用void
指针,这意味着你的代码可能看起来像这样:
SubType *p = new SubType;
BaseType* pB = (BaseType*)p;
delete pB;
在这种情况下,即使BaseType
具有适当的虚拟构造函数,如果SubType
不是从BaseType
派生的,则仍然可能存在未定义的行为。在这里,普通的C型演员阵容不是很幸运。
但若您要使用dynamic_cast
,编译器很可能不允许您这样做,以防p
并没有指向多态类型的对象。即使p
指向多态类型的对象,但BaseType
不会是SubType
的基类型,dynamic_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;
- 我在 IDA 或 dbg 或 olly 上看到的内存是否与我在 RAM 上实时加载的内存相同?
- 访问"std::vector"的保留但未调整大小的内存作为原始内存是否安全?
- 本地分配的内存是否可以用于将来使用?
- 多次分配内存是否一次性需要更多时间?
- 删除矢量的尾部(通过擦除)内存是否有效
- 如何找出内存是否属于堆或堆栈
- C++:提升:托管共享内存是否需要信号量锁
- 在 C/C++ 中在特定地址边界上对齐内存是否仍能提高 x86 性能?
- 检查内存是否在堆上
- C++内存 - 是否需要删除使用 'new' 创建的基元类型变量?
- 如果通过委托给“malloc”的重载“new[]”分配,“释放”内存是否安全
- 分配给 cpp 中定义的全局静态变量的内存是否在 C++ 中删除其类的实例后释放
- 我的 265GB RAM 笔记本电脑上的内存是否超过 8GB
- 在动态内存分配中,在程序终止并且忘记释放内存后,该内存是否保持分配状态
- 这些二维数组(C++)的内存是否不足
- 如果我在 for 中声明一个对象,它的内存是否会在那之后被释放?
- 二进制搜索树(如何在插入时检查内存是否不足)
- 用new重新分配内存是否安全
- 在构造函数初始化列表中分配内存是否存在任何问题
- 内存映射内存是否可能