说我有以下C ++:
char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;
根据C ++标准,这是否安全?我是否需要转回char*
,然后使用delete[]
?我知道它在大多数C ++编译器中都有效,因为它是普通的普通数据,没有析构函数。是否保证安全?
答案 0 :(得分:9)
不能保证安全。这是C ++ FAQ lite中的相关链接:
[16.13]删除某些内置类型的数组([]
,char
等)时,是否可以删除int
?
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
答案 1 :(得分:6)
不,这是未定义的行为 - 编译器可以合理地做一些不同的事情,并且正如thudbang链接到的C ++ FAQ条目所说,operator delete[]
可能会被重载以执行与{{1}不同的操作}。你有时可以侥幸逃脱它,但是对于你不能的情况,养成将delete []与new []匹配的习惯也是一种好习惯。
答案 2 :(得分:4)
我非常怀疑。
有许多可疑的释放内存的方法,例如,您可以在delete
数组(而不是char
)上使用delete[]
,它可能会正常工作。我blogged详细介绍了这一点(为自我链接道歉,但它比重写它更容易。)
编译器不是平台的问题。大多数库将使用底层操作系统的分配方法,这意味着相同的代码在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
运算符也可能是一种选择,但我从未喜欢这样做。)
答案 3 :(得分:2)
C ++标准[5.3.5.2]声明:
如果操作数具有类类型,则通过调用上述转换将操作数转换为指针类型 函数和转换后的操作数用于代替本节其余部分的原始操作数。在任何一个 或者,delete的操作数的值可以是空指针值。 如果它不是空指针值,则在第一个 替代(删除对象),delete的操作数的值应该是指向非数组对象或指向a的指针 子对象(1.8)表示这种对象的基类(第10节)。如果不是,则行为未定义。在第二 替换(删除数组),delete的操作数的值应该是由前一个产生的指针值 array new-expression.77)如果不是,则行为未定义。 [注意:这意味着delete-expression的语法 必须匹配new分配的对象的类型,而不是new-expression的语法。 - 注意事项] [注意:一个指针 const类型可以是delete-expression的操作数;没有必要抛弃它的常数(5.2.11) 指针表达式在用作delete-expression的操作数之前。 - 后注]
答案 4 :(得分:2)
这是一个与我在这里回答的问题非常类似的问题:link text
简而言之,不,根据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
,因为这些(在没有类重写的情况下)由{{1}调用和new
表达式可以(小心!)组合使用。
答案 5 :(得分:0)
虽然应该工作,但我认为你不能保证它是安全的,因为SOME_STRUCT不是char *(除非它只是一个typedef)。
此外,由于您使用的是不同类型的引用,如果继续使用* p访问,并且内存已被删除,则会出现运行时错误。
答案 6 :(得分:0)
如果指向和的内存指向的指针都是POD,那么这将正常工作。在这种情况下,无论如何都不会调用析构函数,并且内存分配器不知道或不关心存储在存储器中的类型。
对于非POD类型,这是唯一的情况,如果指针对象是指针的子类型(例如,您指向带有Vehicle *的Car)并且指针的析构函数已被声明为虚拟。
答案 7 :(得分:0)
这是不安全的,到目前为止没有回应强调这样做的疯狂。如果你认为自己是一名真正的程序员,或者想成为一名团队中的专业程序员,那就干脆就不要这样做。你只能说你的结构目前包含非析构函数 ,但是你为将来铺设了一个令人讨厌的编译器和系统特定的陷阱。此外,您的代码不太可能按预期工作。你可以期待的最好的是它不会崩溃。但是我怀疑你会慢慢得到内存泄漏,因为通过new的数组分配经常在字节 before 中为返回的指针分配额外的内存。你不会释放你认为自己的记忆。一个好的内存分配例程应该像Lint等工具那样找到这种不匹配的方法。
只是不要这样做,并且从脑海中清除思维过程导致你甚至考虑这样的废话。
答案 8 :(得分:0)
我已将代码更改为使用malloc / free。虽然我知道MSVC如何为普通旧数据实现new / delete(在这种情况下SOME_STRUCT是一个Win32结构,如此简单的C),我只是想知道它是否是一种便携式技术。
不是,所以我会使用的东西。
答案 9 :(得分:0)
如果使用malloc / free而不是new / delete,malloc和free将不关心类型。
因此,如果您使用类似C的POD(普通旧数据,如内置类型或结构),您可以使用malloc某种类型,然后释放另一种类型。 请注意,即使有效,这种风格也很差。