通过不同类型的指针删除缓冲区?
说我有以下C ++:
char *p = new char[cb]; SOME_STRUCT *pSS = (SOME_STRUCT *) p; delete pSS;
根据C ++标准,这安全吗?我需要先转换回char *
然后使用delete []
吗?我知道它可以在大多数C ++编译器中使用,因为它是普通数据,没有析构函数。是否保证安全?
解决方案
回答
不,这是未定义的行为,编译器可能会做一些不同的事情,正如thudbang链接到的C ++ FAQ条目所述," operator delete []"可能会被重载以执行与" operator delete"不同的事情。有时我们可以摆脱它,但是对于无法使用delete []与new []进行匹配的习惯,这也是一种好习惯。
回答
不保证安全。这是C ++常见问题精简版中的相关链接:
[16.13]删除某些内置类型(" char"," int"等)的数组时,可以删除" []"吗?
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
回答
尽管这应该可行,但我认为我们不能保证它的安全性,因为SOME_STRUCT不是char *(除非它只是typedef)。
此外,由于使用的引用类型不同,如果继续使用* p访问并且内存已删除,则会出现运行时错误。
回答
C ++标准[5.3.5.2]声明:
If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section. In either alternative, the value of the operand of delete may be a null pointer value. If it is not a null pointer value, in the first alternative (delete object), the value of the operand of delete shall be a pointer to a non-array object or a pointer to a subobject (1.8) representing a base class of such an object (clause 10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of delete shall be the pointer value which resulted from a previous array new-expression.77) If not, the behavior is undefined. [ Note: this means that the syntax of the delete-expression must match the type of the object allocated by new, not the syntax of the new-expression. —end note ] [ Note: a pointer to a const type can be the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer expression before it is used as the operand of the delete-expression. —end note ]
回答
我对此表示高度怀疑。
释放内存的方式有很多可疑的方式,例如,我们可以在char数组上使用delete(而不是delete []),这可能会很好地工作。我在博客上详细介绍了这一点(对自链接表示歉意,但是比重写所有内容都容易)。
编译器不是平台的问题。大多数库将使用基础操作系统的分配方法,这意味着相同的代码在Mac,Windows,Linux上的行为可能有所不同。我已经看到了这样的示例,并且每一个都是可疑的代码。
最安全的方法是始终使用相同的数据类型分配和释放内存。如果要分配char
并将它们返回到其他代码,最好提供特定的分配/取消分配方法:
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
运算符,但我从来不喜欢这样做。)
回答
如果指向的内存和我们指向的指针均为POD,则此方法正常。在这种情况下,无论如何都不会调用析构函数,并且内存分配器不知道或者不在乎存储在内存中的类型。
对于非POD类型,唯一的情况是可以的,如果指针是指针的子类型(例如,我们指向的是带有Vehicle *的Car)并且指针的析构函数已声明为虚拟。
回答
这是不安全的,到目前为止,尚未有任何回应足够强调这样做的疯狂性。如果我们认为自己是一名真正的程序员,或者曾经想成为团队中的专业程序员,那就根本不要这样做。我们只能说结构目前包含非析构函数,但是我们为将来的构建可能是令人讨厌的编译器和系统特定陷阱。另外,代码不太可能按预期工作。我们可以希望的最好的是它不会崩溃。但是我怀疑我们会慢慢出现内存泄漏,因为通过new进行的数组分配通常会在返回的指针之前的字节中分配额外的内存。我们将不会释放自己以为的记忆。良好的内存分配例程应该可以解决这种不匹配问题,例如Lint等工具也可以解决这一问题。
根本就不要那样做,并从思维中清除掉所有导致我们甚至考虑这种胡说八道的思维过程。
回答
我将代码更改为使用malloc / free。虽然我知道MSVC如何为纯旧数据实现新/删除(在这种情况下,SOME_STRUCT是Win32结构,所以很简单C),但我只是想知道它是否是一种可移植的技术。
不是的,所以我将使用正确的东西。
回答
如果我们使用malloc / free而不是new / delete,则malloc和free将不在乎类型。
因此,如果我们使用的是类似C的POD(简单的旧数据,例如内置类型或者结构),则可以分配某种类型,然后释放另一种类型。请注意,即使工作正常,这种样式也不好。
回答
这与我在这里回答的问题非常相似:链接文本
简而言之,不,根据C ++标准,这并不安全。如果由于某种原因,我们需要在内存区域中分配的SOME_STRUCT对象的大小与size_of(SOME_STRUCT)
有所不同(并且最好更大!),那么最好使用原始分配函数,例如全局operator new
来执行分配,然后在原始存储器中以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
表达式适当地调用。可以(小心!)组合使用。