英文:
Can an object with uninitialized fields be safely added in std::vector?
问题 {#heading}
在以下程序中,结构体 A
的默认构造函数未初始化其字段 v
。然后,在一个常量表达式中,使用 A()
对象对 std::vector<A>
进行了emplace操作:
#include <vector>
struct A {
constexpr A() noexcept {}
int v;
};
constexpr bool f() {
std::vector<A> as;
as.reserve(1);
as.emplace_back();
return true;
}
static_assert( f() );
MSVC编译器对未初始化变量的读取发出投诉:
<source>(14): error C2131: expression did not evaluate to a constant
<source>(11): note: failure was caused by a read of an uninitialized symbol
<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<A>
is emplaced with A()
object:
#include <vector>
struct A {
constexpr A() noexcept {}
int v;
};
constexpr bool f() {
std::vector<A> as;
as.reserve(1);
as.emplace_back();
return true;
}
static_assert( f() );
MSVC compiler complains about the reading of uninitialized variable:
<source>(14): error C2131: expression did not evaluate to a constant
<source>(11): note: failure was caused by a read of an uninitialized symbol
<source>(11): note: see usage of 'A::v'
But both GCC and Clang are fine with the program. Online demo: https://godbolt.org/z/addx11aTT
Which compiler is correct here?
答案1 {#1}
得分: 1
看起来MSVC报告了一个读取错误。显然,通过评估然后丢弃emplace_back()
返回的引用形式,而不仅仅是丢弃它。MSVC在一个简化版本中展示了一个bug。请参见下文。
问题不在于向量中的分配,而是emplace_back()
是一个返回表达式的方法,是对添加的元素的引用。
这也可以通过以下方式看出,它创建了一个A对象,提供了对它的引用,然后,在评估引用时,在MSVC中引发了错误。它不应该这样,正如@user17732522在评论中指出的那样。它应该被丢弃为未使用的lvalue。
struct A {
constexpr A() noexcept {}
int v;
};
constexpr bool f() {
A a;
A& b = a;
// b; // 取消注释这一行会导致MSVC失败
return true;
}
static_assert(f());
int main() {}
编译正常,但如果评估引用对象b
,则会出现以下错误:
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.
struct A {
constexpr A() noexcept {}
int v;
};
constexpr bool f() {
A a;
A\& b = a;
// b; // uncommenting this causes MSVC to fail
return true;
}
static_assert(f());
`int main() {}
`
Compiles fine but if the b
, a reference to the objects is evaluated this error ensues:
Message failure was caused by a read of an uninitialized symbol
This is a MSVC bug.