通过不同类型的指针删除缓冲区?

时间:2008-09-16 10:01:01

标签: c++ pointers memory-management

说我有以下C ++:

char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;

根据C ++标准,这是否安全?我是否需要转回char*,然后使用delete[]?我知道它在大多数C ++编译器中都有效,因为它是普通的普通数据,没有析构函数。是否保证安全?

10 个答案:

答案 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;
}

(重载newdelete运算符也可能是一种选择,但我从未喜欢这样做。)

答案 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 ++最接近的mallocfree,因为这些(在没有类重写的情况下)由{{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某种类型,然后释放另一种类型。 请注意,即使有效,这种风格也很差