Shouldn't std::optional contain its value while the emplacing constructor is executing?
Asked Answered
O

0

7

In real code, constructors can be very complex and so the emplace of a std::optional can query the status of the optional itself. When this happens it's usually a bit more convoluted, but here is a (contrived) minimal example:

#include <iostream>
#include <optional>

struct Thing {
    Thing();
};

std::optional<Thing> othing;

Thing::Thing() {
    std::cout << othing.has_value() << std::endl;
}

int main() {
    othing.emplace();
}

For all three major standard library implementations, this yields false. In other words during the execution of the emplacing constructor, the optional does not contain a value.

From an implementation perspective, this means that the value is constructed in-place first and afterwards some bookkeeping variable is set. And this is indeed the case in MSVC, libc++ and libstdc++.

Now the relevant part of the standard reads

[...] When an instance of optional<T> contains a value, it means that an object of type T, referred to as the optional object's contained value, is allocated within the storage of the optional object.

Interestingly this doesn't use the clearly defined lifetime of the contained object (I suppose because this can be forcibly be ended from outside, e.g. othing->~Thing()), but the term allocated within the storage. The standard usually speaks of allocation in the context of dynamic memory and in these cases, allocation clearly takes place before construction.

So I would argue that the mentioned standard library implementations are not compliant, the bookkeeping variable should be set right before construction starts.

Under this assumption one question remains: Are the implementations better than the standard and isn't it rather the latter that needs to be fixed or clarified? I don't think so: During construction of large objects it's perfectly valid and common to access already initialized subobjects, so this should be possible for objects contained in an optional as well.

So are my considerations right? Or is my interpretation of the term allocated within incorrect? And are there arguments against my standpoint of what's the RightThing™ to do?

Oringas answered 29/4, 2021 at 11:28 Comment(3)
I wouldn't want to be told that it contains a not-yet or incompletely constructed value. This seems totally right to me. You could submit a paper to get better wording in the legalese!Comprador
cplusplus.github.io/LWG/issue2414. There's no way this is going to be anything other than undefined (or perhaps implementation-defined to be undefined).Verlaverlee
@Verlaverlee I think this is already the answerOringas

© 2022 - 2024 — McMap. All rights reserved.