8

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?

5
  • I don't see where value of v is read in this code (as reported by the message) -- just conjecturing here, perhaps it is an interaction with MSVC debug-build code to detect uninitialized access? Commented Aug 10, 2023 at 22:03
  • @M.M I believe it is somewhere in reallocation part of the vector Commented Aug 10, 2023 at 22:15
  • 1
    @Dmitry there cannot be any reallocation of vector containing objects that exist, in this exact program Commented Aug 10, 2023 at 22:24
  • 1
    as.emplace_back(); returns an unused reference to the appended A object. And that contains an uninitialized value. Commented Aug 10, 2023 at 22:35
  • 2
    Regardless of whether or not the shown program is well-formed (which I think it is), in order to "safely" use this construction one must not perform any operation on std::vector that might copy/move the indeterminate value. So no modifications except decreasing capacity, increasing capacity only from empty state, and adding/removing elements at/from the end (if capacity is free). No copying of the vector itself either. Commented Aug 10, 2023 at 23:17

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

8 Comments

And why would b; cause a read? This looks like a compiler bug to me.
@user17732522 reading an uninitialized value is UB. And b is an expression that gets evaluated even if not used.
But evaluating b doesn't cause any read. It is a lvalue expression to which no lvalue-to-rvalue conversion is applied.
@user17732522 it's an expression that is the value of the object b refers to. That is a.
The lvalue result of the expression is the object a, not the value of the object (which would be a prvalue). No value of a is read.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.