【问题标题】:Weird c++ construct奇怪的 C++ 构造
【发布时间】:2015-05-07 08:13:04
【问题描述】:

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

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

Whole source code(line 41)

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

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

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

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

重要信息:我正在使用 Visual Studio 2013。

【问题讨论】:

  • 你能显示这个链接器错误吗?
  • 重新打开,因为这不是重复的。问题还在于修改是否有不利影响。
  • @Shoter:欢迎来到 Stackoverflow。请注意,链接到相关代码不是一个好习惯,因为链接往往会过时。请在您的问题中发布相关摘录(例如所有涉及的变量的类型)。您还应该始终发布您收到的确切错误消息。这使人们更容易回答您的问题,并使其对有类似问题的其他人更有用。
  • 链接器错误:4>e:\openttd\trunk\src\3rdparty\squirrel\squirrel\squtils.h(38): 致命错误 C1001: 编译器发生内部错误。 4>(编译器文件'f:\dd\vctools\compiler\utc\src\p2\main.c',第228行)我的行号略有不同。

标签: c++


【解决方案1】:

这是标准的placement new。你可能错过了

#include <new>

【讨论】:

  • Visual Studio 在链接过程中仍然崩溃。感谢您的帮助!
【解决方案2】:

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

【讨论】:

  • 感谢您的回答。我会尽快修复代码。谢谢你的回答!
【解决方案3】:

这是新位置

new (addr) T(...)

在内存地址addr 处构造T 对象。这里它在地址&amp;_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&amp;),并且因为使用了新的放置。 (例如,如果 T 包含引用成员并且是不可变的)

【讨论】:

  • 我认为 microsoft Visual Studio 2013 不能很好地处理新的放置,因为它会使链接器崩溃:/。感谢您的帮助!
  • 这是最简洁的答案
  • 可能在T 类中有一个声明T&amp; operator=(const T&amp;);,而.cpp 中没有定义。这有时用于指示在 C++11 之前未实现方法(具有= delete)(并导致链接器错误)。放置 new 可能不会使链接器崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-05
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
相关资源
最近更新 更多