3

Consider the following code:

#include <variant>
#include <cassert>

struct foo {
  foo() noexcept;
  foo(const foo&) noexcept = default;
  foo(foo&&) noexcept = default;
  foo& operator=(const foo&) noexcept = default;
  foo& operator=(foo&&) noexcept = default;
};

std::variant<std::monostate, foo> var;  

foo::foo() noexcept {
    assert(!var.valueless_by_exception());
};

int main() {
    var.emplace<foo>();
}

With libstdc++ (from GCC 11), this works, but with libc++ (from LLVM 12), and MSVC, the assert fails.

Which standard library implements the correct behaviour ? At no point any exception is thrown, and my type is entirely noexcept, so I'd expect "valueless_from_exception" to never be true.

To quote the standard (https://timsong-cpp.github.io/cppwp/n4861/variant#status):

A variant might not hold a value if an exception is thrown during a type-changing assignment or emplacement.

here I am clearly not in that case.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
Jean-Michaël Celerier
  • 7,412
  • 3
  • 54
  • 75
  • Note that `valueless_by_exception` doesn't mean "An exception was thrown." It means "variant holds no value". After the previous variant value is destructed and before the new variant value is created, the variant has no value, so I would expect it to be valueless during the interim. – Raymond Chen Sep 03 '21 at 23:17
  • Hmm, but everything that I am reading says that the only way for a variant to not hold a value is by an exception ? I'd assume the lifetime of the new value to begin as soon as the value's construction has begun (and thus the variant "holding it" from there), like libstdc++ ensures. – Jean-Michaël Celerier Sep 04 '21 at 06:51

1 Answers1

3

The standard doesn't currently provide an answer to your question, but the direction that LWG appears to be moving in is that your code will have undefined behaviour.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312