假设我有以下 C++:

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

根据 C++ 标准,这安全吗?我需要投射回 char* 然后使用 delete[]?我知道它可以在大多数 C++ 编译器中工作,因为它是普通数据,没有析构函数。能保证安全吗?

有帮助吗?

解决方案

不能保证它是安全的。以下是 C++ FAQ lite 中的相关链接:

[16.13] 我可以放弃吗 [] 删除某些内置类型的数组时(char, int, , ETC。)?

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13

其他提示

不,这是未定义的行为 - 编译器可能会做一些不同的事情,正如 C++ FAQ 条目所述 轰轰烈烈 链接到说, operator delete[] 可能会超载去做一些不同的事情 operator delete. 。有时您可以逃脱它,但在您无法逃脱的情况下,养成将 delete[] 与 new[] 匹配的习惯也是一个好习惯。

我非常怀疑。

有很多有问题的释放内存的方法,例如您可以使用 delete 在你的 char 数组(而不是 delete[])并且它可能会正常工作。我 写博客 详细说明这一点(对自链接表示歉意,但这比全部重写更容易)。

与其说是编译器的问题,不如说是平台的问题。大多数库将使用底层操作系统的分配方法,这意味着相同的代码在 Mac 和 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 运算符也可能是一种选择,但我从来不喜欢这样做。)

C++ 标准 [5.3.5.2] 声明:

如果操作数具有类类型,则通过调用上述转换功能将操作数转换为指针类型,并在本节的其余部分中使用转换后的操作数代替原始操作数。在任何一个方面,删除的操作数的值可能是无效的指针值。 如果它不是零指针值,则在第一个替代方案(删除对象)中,删除的操作数的值应为非阵列对象的指针或代表代表此类基类的子对象的指针(1.8)一个对象(第10条)。如果不是,则行为未定义。在第二个替代方案(DELETE数组)中,删除操作数的值应为由以前的数组new-Expression造成的指针值。77)如果没有,则行为是未定义的。[ 笔记:这意味着删除表达的语法必须匹配新表达式分配的对象的类型,而不是新表达的语法。——尾注] [ 笔记:指向const类型的指针可以是删除表达的操作数;在用作删除表达的操作数之前,不必抛弃指针表达式的构成(5.2.11)。——尾注]

这是一个与我在这里回答的问题非常相似的问题: 链接文本

简而言之,不,根据 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 并且因为这些(在没有类覆盖的情况下)被适当地调用 newdelete 它们可以(小心!)组合使用。

虽然这 应该 工作,我认为你不能保证它是安全的,因为 SOME_STRUCT 不是 char* (除非它只是一个 typedef)。

此外,由于您使用不同类型的引用,如果您继续使用 *p 访问,并且内存已被删除,您将收到运行时错误。

如果内存被指向,这将工作正常 你所指向的指针都是POD。在这种情况下,无论如何都不会调用析构函数,并且内存分配器不知道也不关心内存中存储的类型。

对于非 POD 类型来说,唯一可以接受的情况是,被指者是指针的子类型(例如您正在指向带有车辆*的汽车,并且指针的析构函数已被声明为虚拟。

这是不安全的,而且迄今为止没有任何回应足够强调这样做的疯狂性。如果您认为自己是一个真正的程序员,或者曾经想在团队中作为专业程序员工作,那么就不要这样做。你只能说你的结构体包含非析构函数 眼下, ,但是您正在为未来设置一个可能令人讨厌的编译器和系统特定的陷阱。此外,您的代码不太可能按预期工作。您所能期望的最好的结果就是它不会崩溃。但是我怀疑你会慢慢地遇到内存泄漏,因为通过 new 进行数组分配经常会以字节为单位分配额外的内存 事先的 到返回的指针。你不会释放你认为的记忆。一个好的内存分配例程应该能够识别出这种不匹配,就像 Lint 等工具一样。

只是不要这样做,并从你的头脑中清除任何导致你思考这种废话的思维过程。

我已更改代码以使用 malloc/free。虽然我知道 MSVC 如何为普通旧数据实现新/删除(本例中的 SOME_STRUCT 是 Win32 结构,所以简单的 C),但我只是想知道这是否是一种可移植技术。

它不是,所以我会使用一些东西。

如果您使用 malloc/free 而不是 new/delete,则 malloc 和 free 不会关心类型。

因此,如果您使用类似 C 的 POD(普通旧数据,如内置类型或结构),您可以 malloc 某些类型,然后释放另一个类型。 请注意,即使它有效,这种风格也很糟糕.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top