在std::vector中可以安全地添加具有未初始化字段的对象吗?

huangapple go评论224阅读模式
英文:

Can an object with uninitialized fields be safely added in std::vector?

问题

在以下程序中,结构体 A 的默认构造函数未初始化其字段 v。然后,在一个常量表达式中,使用 A() 对象对 std::vector<A> 进行了emplace操作:

  1. #include <vector>
  2. struct A {
  3. constexpr A() noexcept {}
  4. int v;
  5. };
  6. constexpr bool f() {
  7. std::vector<A> as;
  8. as.reserve(1);
  9. as.emplace_back();
  10. return true;
  11. }
  12. static_assert( f() );

MSVC编译器对未初始化变量的读取发出投诉:

  1. <source>(14): error C2131: expression did not evaluate to a constant
  2. <source>(11): note: failure was caused by a read of an uninitialized symbol
  3. <source>(11): note: see usage of 'A::v'

但GCC和Clang编译器都对该程序没有问题。在线演示:https://godbolt.org/z/addx11aTT

哪个编译器是正确的?

英文:

In the following program, default constructor of struct A does not initialize its field v. Then in a constant expression, std::vector&lt;A&gt; is emplaced with A() object:

  1. #include &lt;vector&gt;
  2. struct A {
  3. constexpr A() noexcept {}
  4. int v;
  5. };
  6. constexpr bool f() {
  7. std::vector&lt;A&gt; as;
  8. as.reserve(1);
  9. as.emplace_back();
  10. return true;
  11. }
  12. static_assert( f() );

MSVC compiler complains about the reading of uninitialized variable:

  1. &lt;source&gt;(14): error C2131: expression did not evaluate to a constant
  2. &lt;source&gt;(11): note: failure was caused by a read of an uninitialized symbol
  3. &lt;source&gt;(11): note: see usage of &#39;A::v&#39;

But both GCC and Clang are fine with the program. Online demo: https://godbolt.org/z/addx11aTT

Which compiler is correct here?

答案1

得分: 1

看起来MSVC报告了一个读取错误。显然,通过评估然后丢弃emplace_back()返回的引用形式,而不仅仅是丢弃它。MSVC在一个简化版本中展示了一个bug。请参见下文。

问题不在于向量中的分配,而是emplace_back()是一个返回表达式的方法,是对添加的元素的引用。

这也可以通过以下方式看出,它创建了一个A对象,提供了对它的引用,然后,在评估引用时,在MSVC中引发了错误。它不应该这样,正如@user17732522在评论中指出的那样。它应该被丢弃为未使用的lvalue。

  1. struct A {
  2. constexpr A() noexcept {}
  3. int v;
  4. };
  5. constexpr bool f() {
  6. A a;
  7. A& b = a;
  8. // b; // 取消注释这一行会导致MSVC失败
  9. return true;
  10. }
  11. static_assert(f());
  12. int main() {}

编译正常,但如果评估引用对象b,则会出现以下错误:

  1. Message failure was caused by a read of an uninitialized symbol

这是一个MSVC的bug。

英文:

Looks like MSVC is reporting a read error. Apparently by evaluating then discarding the returned reference form emplace_back() rather than just discarding it. MSVC does demonstrate a bug in a simplified version. See below.

The problem isn't allocation in vector, it's that the emplace_back() is a method that returns an expression, a reference to the added element.

This can be also seen by the following which creates an A object, provides a reference to it, then, when the reference is evaluated it causes an error in MSVC. It should not, as @user17732522 pointed out in comments. It should be discarded as an unused lvalue.

  1. struct A {
  2. constexpr A() noexcept {}
  3. int v;
  4. };
  5. constexpr bool f() {
  6. A a;
  7. A&amp; b = a;
  8. // b; // uncommenting this causes MSVC to fail
  9. return true;
  10. }
  11. static_assert(f());
  12. int main() {}

Compiles fine but if the b, a reference to the objects is evaluated this error ensues:

  1. Message failure was caused by a read of an uninitialized symbol

This is a MSVC bug.

huangapple
  • 本文由 发表于 2023年8月11日 05:07:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76879315.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定