New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
the lifetime of the variant members of union class objects operated by memcpy #5213
Comments
may have some connections with issue #5193 |
It cannot be sure according to [intro.object] p10 (... that operation implicitly creates and starts the lifetime of zero or more objects of implicit-lifetime types ...), because the invocation may even create no object (in this case, I'm not sure whether implicit object creation can end the lifetime of a living object. If so, the effect of the Consider this example which may be unrelated to the existing active member: union U { int i; char c; };
U u1{.i = 1};
alignas(U) unsigned char buf[sizeof(U)]; // #1
std::memcpy(buf, &u1, sizeof(U)); // #2
auto p = std::launder(reinterpret_cast<U*>(buf)); // #3
auto consume = [](auto){};
if (std::rand() < RAND_MAX / 2)
consume(p->i); // #4
else
consume(p->c); // #5 Here |
IMO, if the operation of the implicitly creating object creates at least one object, then that living object will be ended its lifetime since the newly created object reuses the storage occupied by that living object. I'm not 100% sure that I correctly understand [intro.object] p10.
So, in order to make the program be well-defined, the lifetime of Incidentally, it is reasonable that the behavior of that |
I don't think so. IIUC only one member is needed to be alive as only one of
In every execution of the program, only one of these two mutually exclusive cases is encounted, so the program has defined behavior. |
The implicitly creating objects operation is at
As I said, |
Yes, we can't know which substatement will be executed, and can't determine the set of created objects at
I don't think [basic.life] p1 convers the cases of implicit object creation, although the current wording is confusing for me.
It's arguble whether the wording permits implicit object creation - because the latter never performs initialization.
Here might be hazy, but I don't think that unions are special. IMO the wording of [basic.life] should be harmonized with [intro.object]. |
In my opinion, such an operation should scan the subsequent codes to one-off determine what the set is. It seems that you consider such a process is dynamic, looks like the determination of the set will be deferred and such set will be dynamically changed according to what the concrete subsequent execution needs(the set includes
unions are special. we don't need to be concerned about which member subobjects can be created and be begun its lifetime, as long as they are of implicitly-lifetime types and are needed by the program. However, as nominated in above, we do concern about such issues when they are variant members. If your interpretation of "set of implicitly creating objects" is correct, I think |
Oh... I should use
I guess the such set doesn't need to be dynamically changed although it can't be statically determined. The set of "possible sets of implicitly created object within a given storage by a given explicit operation" may be considered dynamically shrinking. When all operations on the storage has been done, every element in "that set of sets" can be considered as "the set of implicitly creating objects" (which is unchanged during these operations), and no UB happens if the "that set of sets" hasn't become empty. |
There is an example that can prove
is not true if (std::rand() < RAND_MAX / 2){
consume(p->i); // #4
goto label;
}else{
label:
consume(p->c); // #5
} In this example, once the condition is |
No. The dynamically shrinking set I meant is the set of possible sets of implicitly created objects, whose elements are sets of objects. Given the example you showed
IMO before the execution of the statement (the set at that point is called I for exposition),
Then X, Y, and Z are pairwise disjoint, and I is the union set of X, Y, and Z. None of element of I includes both If the the condition is |
Ah, after reading [intro.object] p10 more carefully. You're correct. I would prefer to consider The operation can implicitly create and start the lifetime for either
since the lifetimes of
|
Every time I see this issue, I facepalm from its inconsistent/half-baked logic.
No (new) storage is obtained == no lifetime is started. I'd say this issue should be closed as NAD with a comment that «obtained ≠ allocated» (see https://stackoverflow.com/a/58356588). |
Whats wrong with this rule from implicit-object creation POV? |
Let's continue the discussion of obtaining storage here (instead of #4553) ... It'll be confusing to me to just say the same region of storage can be obtained more than once. Perhaps it makes more sense to clarify that storage obtaining and the start of lifetime are not one-to-one corresponding.
Maybe I referred the next bullet ([basic.life]/1.2) at that time. [basic.life]/1.1 probably has no extraneous problem on implict object creation. If I understand correctly, [basic.life]/1.2 is now problematic, because the lifetime of an implicitly created object starts without any kind of initialization (including vacuous initialization). |
It is «obtained [once] per object», not just abstractly «obtained»
The lifetime of implicitly created objects is covered by http://eel.is/c++draft/intro.object#10, not [basic.life] |
This is still confusing. Would it be better to avoid saying "storage of ... is obtained"? |
CWG2675 seems to be related to starting the lifetime of a union member. Although only |
Consider this example
At
#1
, the variant memberU::i
of the objectu1
is active, while at#2
, the variant memberU::c
of the objectu2
is active. Since [cstring.syn] p3 saysThus, before the copying starts, what can be sure is that an object of type
U
is implicitly created in the specified storage. In addition, the lifetime of eitherU::i
orU::c
can start due to the "implicitly create objects" but not both. Which is regulated by [class.union.general] p2Since, immediately prior to copying, we cannot determine which variant member has begun its lifetime in the newly created union object that occupies the storage of
u2
. Also, after the copying, we also cannot determine which one is active. Is itU::i
because the corresponding variant is active in the source? Or, Is itU::c
since it's the one selected by the "implicitly creating objects" operation.The text was updated successfully, but these errors were encountered: