怪异的c++结构

Weird c++ construct

本文关键字:结构 c++      更新时间:2023-10-16

我想为自己编译openttd源代码。它使用的是Squirell库,由于链接器错误,我无法编译它。我查阅了无法编译的代码,发现了我(和链接器:D)无法理解的奇怪结构:

new ((void *)&_vals[i]) T(v._vals[i]);

完整源代码(第41行)

我修改了代码,现在看起来是这样的:

_vals[i] = *(new  T(v._vals[i]));

我不知道我是否以良好的方式修改了代码。我希望我做到了。游戏现在并没有崩溃,所以也许它有可能运行良好。

有人能解释一下为什么这个构造没有任何编译时错误,只是链接器错误吗?这个代码到底在做什么?

重要信息:我使用的是visualstudio2013。

这是新的标准布局。你可能错过了

#include <new>

您的修改引入了内存泄漏。以前,使用placementnew将新对象构造到已分配的内存中。现在使用new创建一个对象,然后将其复制到_vals中。但是,您永远不会在原件上调用delete

这是放置新

new (addr) T(...)

在存储器地址addr处构造T对象。在这里,它在地址&_vals[i]处构造它,也就是说,它覆盖对象_vals[i]。该地址被广播到void*,即原始存储器地址。

当对象是不可变的或没有实现赋值运算符时,这有时用于重新构造对象。例如

A a(1);
...
a.~A(); // needed as otherwise a would not get destructed
new (&a) A(2);
...

使新的A对象位于与旧对象相同的地址,并保持对它的引用和指针有效。

这是一个低级操作,可能会导致问题,即当不确定addr是否适合对象时,内存对齐。

修改后的代码在堆上构造一个新对象,并将其分配给现有对象,然后泄漏它

_vals[i] = T(v._vals[i]);

链接器错误可能是因为没有T::operator=(const T&),并且因为使用了新的放置。(例如,如果T包含一个引用成员并且是不可变的)