Open Eisenwave opened 1 year ago
See also https://github.com/cplusplus/CWG/issues/40#issuecomment-1139501123.
Related: cplusplus/draft#4802.
Perhaps we want zero-initialization starts the lifetime of an object of a trivial type, but not a std::string
.
It may also be desired that the lifetime of every subobject starts when its type is trivial (the criteria may be slightly different) and in an active union member.
CWG2821
This program raises SIGSEGV with libstdc++ (Godbolt link):
#include <string>
#include <thread>
#include <iostream>
void fun()
{
thread_local std::string s = "str"; // On libstdc++, s can't have static initialization.
std::thread([]{
// N.B. the constructor hasn't been called for s of this thread.
std::cout << static_cast<int>(s[s.size()]) << '\n';
}).join();
}
int main()
{
fun();
}
It doesn't seem possible to guarantee well-defined behavior for a zero-initialized but not yet dynamically initialized std::string
object. Should we treat its lifetime being started?
With the current proposed resolution, I think we can strike the part about union members. Given that objects will not begin lifetime until "any initialization is complete (including vacuous initialization)", therefore, the fact that the non-initialized members of the union do not begin their lifetime falls out naturally out of the second bullet, because they do not have any initialization (yet).
It doesn't seem possible to guarantee well-defined behavior for a zero-initialized but not yet dynamically initialized
std::string
object. Should we treat its lifetime being started?
You could ask the same question about a user-written class type where every non-constructor function has, as a precondition, that a constructor has completed.
The fact that std::string
is such a standard library type is a specification issue for LWG, not CWG.
Full name of submitter: Jan Schultke
Reference (section label): [basic.life]
Issue Description
It is popular opinion in the C++ community that the lifetime of an object begins before dynamic initialization, e.g. https://stackoverflow.com/a/42365867/5740428. This is even considered an idiom, e.g.
int x = x;
may be used to suppress warnings about a global variable being unused, and is believed to be well-defined. There are examples in the standard which support this belief. See [basic.start.static] Note 2. The following note considers access tod1
well-defined, implying that its lifetime has begun and its value can be used, even before dynamic initialization:However, not all wording clearly indicates that this is well-defined. In [basic.life] p1.2, it is said that an object's lifetime begins when:
Footnote 23 for [basic.life] p6 mentions an example of an object which's lifetime hasn't begun, but for which storage was allocated:
We are not allowed to use such an object, because according to [basic.life] p7.1:
In summary, footnote 23 suggests that [basic.start.static] Note 2 actually contains undefined behavior because the initialization is not complete, and the lifetime of
d1
has not yet begun, which contradicts the code comments in the note.Furthermore, the singular form of "initialization" in [basic.life] p1.2 could be interpreted in two ways:
The first interpretation makes the aforementioned note undefined behavior, the second makes it well-formed.
Suggested resolution
Remove or reword whichever note contradicts WG21 intent. Assuming the intent is that lifetime begins before dynamic initialization, remove Footnote 23, and update [basic.life] p1.2: