使用placement-new时未定义的行为或内存泄漏

Kal*_*Kal 15 c++ memory-leaks placement-new undefined-behavior

我正在使用此处列出的书籍学习 C++ 中的placement-new 。现在,为了看一些示例,我在其中一篇 SO 帖子中发现了以下片段,声称(给定的示例)具有未定义的行为:

例如,有 UB:

void ub() {
   alignas(string) char buf[sizeof(string)]; // memory is allocated
   new(buf) string("1");                     // string("1") is constructed
} // memory is deallocated but string("1") outlives the memory! 
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,用户声称上述代码片段具有未定义的行为。但我认为它有内存泄漏而不是UB。有人可以告诉我上面的代码片段是否有 UB 或内存泄漏或两者都有,以及我的理解(它有内存泄漏但没有 UB)是否正确。

use*_*522 13

标准中有一句话,其在[basic.life]/5中的含义不是很清楚,它说如果像您引用的示例中那样省略了析构函数调用,那么

任何依赖于析构函数产生的副作用的程序都有未定义的行为。

目前尚不清楚这里的“取决于副作用”是什么意思。如果您认为泄漏内存的副作用是您的程序“依赖”的,那么也许它适用,但我怀疑这是否是预期的阅读内容。

CWG 第 2523 期建议删除此短语并仅用一个非规范注释替换,其中提及在这种情况下不调用析构函数的潜在问题。另请参阅此处的讨论。

除此之外,没有未定义的行为,只是内存泄漏。当然,对于其他类型,string如果您在释放内存之前没有正确调用析构函数,则很容易导致未定义的行为。

在实践中,你不应该让这种情况发生,即使只是为了避免内存泄漏。因此,您实际上可以将其视为未定义的行为。


Gos*_*low 7

在这种情况下,除了明显的内存泄漏之外,您的代码没有任何真正的问题。

不过,您构造的类型的构造函数可能会产生副作用,例如将构造的对象添加到所有此类对象的全局列表中。然后,析构函数将从所述列表中删除该对象,但您永远不会调用析构函数。所以全局列表最终会出现一个悬空指针。

注意:现代 C++ 必须construct_at将您的放置替换为新的。