【问题标题】:deleting a buffer through a different type of pointer?通过不同类型的指针删除缓冲区?
【发布时间】:2010-09-09 09:51:36
【问题描述】:
假设我有以下 C++:
char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;
根据 C++ 标准,这是否安全?我是否需要转换回char*,然后使用delete[]?我知道它适用于大多数 C++ 编译器,因为它是普通数据,没有析构函数。能保证安全吗?
【问题讨论】:
标签:
c++
pointers
memory-management
【解决方案1】:
不,这是未定义的行为 - 编译器可能会做一些不同的事情,正如 thudbang 链接到的 C++ FAQ 条目所说,operator delete[] 可能会被重载以做与 operator delete 不同的事情。有时您可以侥幸逃脱,但在您无法做到的情况下,养成将 delete[] 与 new[] 匹配的习惯也是一种好习惯。
【解决方案3】:
虽然这个应该有效,但我认为你不能保证它是安全的,因为 SOME_STRUCT 不是 char*(除非它只是一个 typedef)。
另外,由于你使用了不同类型的引用,如果你继续使用*p访问,并且内存已经被删除,你会得到一个运行时错误。
【解决方案4】:
C++ 标准 [5.3.5.2] 声明:
如果操作数具有类类型,则通过调用上述转换将操作数转换为指针类型
函数,并且在本节的其余部分中使用转换后的操作数代替原始操作数。在任一
或者,delete 的操作数的值可以是空指针值。 如果不是空指针值,在第一个
替代(删除对象),删除操作数的值应该是指向非数组对象的指针或指向
子对象(1.8),表示这种对象的基类(第 10 条)。如果不是,则行为未定义。在第二
替代(删除数组),删除操作数的值应为前一个产生的指针值
array new-expression.77) 如果不是,则行为未定义。 [注意:这意味着删除表达式的语法
必须匹配 new 分配的对象的类型,而不是 new 表达式的语法。 —尾注] [注:指针
const 类型可以是删除表达式的操作数;没有必要抛弃 constness (5.2.11)
之前的指针表达式用作删除表达式的操作数。 ——尾注]
【解决方案5】:
我非常怀疑。
有很多值得怀疑的释放内存的方法,例如你可以在你的char 数组上使用delete(而不是delete[]),它可能会正常工作。我blogged对此进行了详细说明(为自链接道歉,但它比全部重写更容易)。
编译器不是平台的问题。大多数库将使用底层操作系统的分配方法,这意味着相同的代码在 Mac、Windows 和 Linux 上的行为可能不同。我见过这样的例子,每一个都是有问题的代码。
最安全的方法是始终使用相同的数据类型分配和释放内存。如果您分配chars 并将它们返回给其他代码,您最好提供特定的分配/解除分配方法:
SOME_STRUCT* Allocate()
{
size_t cb; // Initialised to something
return (SOME_STRUCT*)(new char[cb]);
}
void Free(SOME_STRUCT* obj)
{
delete[] (char*)obj;
}
(重载new 和delete 运算符也可能是一种选择,但我从不喜欢这样做。)
【解决方案6】:
如果指向的内存和你指向的指针都是POD,这将正常工作。在这种情况下,无论如何都不会调用析构函数,并且内存分配器不知道也不关心内存中存储的类型。
对于非 POD 类型,唯一可行的情况是,指针对象是指针的子类型(例如,您使用 Vehicle* 指向 Car)并且指针的析构函数已被声明为虚拟。
【解决方案7】:
这是不安全的,到目前为止,没有一个回应足够强调这样做的疯狂。如果您认为自己是真正的程序员,或者曾经想在团队中作为专业程序员工作,请不要这样做。你只能说你的结构目前包含非析构函数,但是你正在为未来埋下一个令人讨厌的编译器和系统特定的陷阱。此外,您的代码不太可能按预期工作。您可以期望的最好的结果是它不会崩溃。但是我怀疑你会慢慢地得到内存泄漏,因为通过 new 的数组分配经常会在返回的指针 prior 字节中分配额外的内存。你不会释放你认为的记忆。一个好的内存分配例程应该能够解决这种不匹配问题,就像 Lint 等工具一样。
干脆不要那样做,从你的脑海中清除掉任何让你想到这些废话的思考过程。
【解决方案8】:
我已将代码更改为使用 malloc/free。虽然我知道 MSVC 如何为普通旧数据实现新/删除(在这种情况下 SOME_STRUCT 是一个 Win32 结构,如此简单的 C),但我只是想知道它是否是一种可移植技术。
它不是,所以我将使用它。
【解决方案9】:
如果你使用 malloc/free 而不是 new/delete,malloc 和 free 不会关心类型。
因此,如果您使用类似 C 的 POD(普通旧数据,如内置类型或结构),您可以 malloc 一些类型,并释放另一种类型。 请注意,即使它有效,这也是一种糟糕的风格。
【解决方案10】:
这是一个与我在这里回答的问题非常相似的问题:link text
简而言之,不,根据 C++ 标准,它是不安全的。如果出于某种原因,您需要在与size_of(SOME_STRUCT) 大小不同的内存区域中分配一个 SOME_STRUCT 对象(并且最好更大!),那么您最好使用全局@987654323 之类的原始分配函数@ 执行分配,然后在原始内存中创建对象实例,其位置为new。如果对象类型没有构造函数,则放置 new 将非常便宜。
void* p = ::operator new( cb );
SOME_STRUCT* pSS = new (p) SOME_STRUCT;
// ...
delete pSS;
这在大多数情况下都有效。如果 SOME_STRUCT 是 POD 结构,它应该始终有效。如果SOME_STRUCT 的构造函数没有抛出并且SOME_STRUCT 没有自定义运算符删除,它也可以在其他情况下工作。这种技术也消除了对任何演员表的需要。
::operator new 和 ::operator delete 是 C++ 中最接近 malloc 和 free 的等价物,因为它们(在没有类覆盖的情况下)被 new 和 delete 表达式酌情调用(使用小心!)组合使用。