Date: Thu, 9 Jul 2026 09:50:51 +0200
śr., 8 lip 2026 o 12:19 mauro russo via Std-Discussion
<std-discussion_at_[hidden]> napisał(a):
>
> wow, thanks Eyal to highlight it, what a coincidence.
>
> In my case, it came out from standard careful read
> while I was forwarding existing information for an
> internal upskill for colleagues.
>
> That said, let me provide answers to Marcin and you, in turn.
>
> For Marcin:
> > I recall this discussion but was this even in single inhrace case too?
> > And if in this simple case the compiler does multiple moves, could this means
> > that the code created by compiler correctly move all data?
> > Like my example in my prev email, I did multiple moves but as a whole
> > it only "move data" once and does not override it after that.
> > And this idiom can be safely nested as only most outer function
> > have data and rest do empty moves.
>
> I would say, the point is not whether the compiler can do it simply or not
> in special cases. The point is that the standard keeps it "unspecified"
> in any case. To me, it means we cannot use it at all. This links to another
> part of your statement:
> < I did multiple moves but as a whole it only "move data" once
> and does not override it after that >
> First, this would be a contradiction. If the operation is done multiple times,
> then it must move from the source multiple times. Or, at least, the current
> wording from the standard should be clarified. Such a kind of 'final effect
> as if the move happens exactly once' was my hope when I first posted the
> question in https://lists.isocpp.org/std-discussion/2026/07/3430.php
> Pls, note that in https://lists.isocpp.org/std-discussion/2026/07/3431.php
> we had Ville who made this try: https://godbolt.org/z/PK3GEav13
> showing that the move is really performed twice.
> Also, I tried something like this: https://godbolt.org/z/rzq5cq5fK
> (and no problems, instead, with the constructors: https://godbolt.org/z/orMY9xvh5 )
> showing that moving twice destroys the information in both source and
> destination. This means that the compilers implementation are really
> following the standard wording about the option to perform the move
> multiple times.
>
Ok, but all compilers scream that this code is broken, this means
this will not be a sneaky error that unexpectedly hits you.
It looks like compilers simply do not bother to implement this because
how many times you need to move data from polymorphic types?
Usually they are heap allocated and you have only base pointers.
It's a bit hard to move from an object like this.
Probably better indead would be if this was an error than a warning.
But its only needed if the virtual base is duplicated in an object, if it's only
one then there is no problem and we do not need to reject code like that.
> About you, Eyal, I see interesting in the stack overflow thread this information:
> there was a change from C++11 to C++14.
> Before C++14, we had that in case of virtual base classes the move assign.op.
> was defined as deleted, and we had the 'unspecified' only for the copy assign.op.
> In my opinion, this should be reverted. It makes no sense at all to unspecifiy
> for the move, which means we cannot use it at all.
> About the cases when it would be complicated to get or not a "good" implicit
> definition... again, I am not necessarily asking for that. It would be an option,
> but I prefer to have it defined as deleted, simple and consistent.
>
> We are having a hot time for C++ around safety.
> IMHO, having an implicit definition that cannot guarantee at all not to destroy
> the information, means to go against safety.
> No guarantee there means useless. More, it means dangerous, because we
> might have it both implicitly declared and implicitly defined.
> We should not bet by relying that the compiler will do it correctly, at least
> for our simple class. If the standard keeps it unspecified, we risk, and even if
> we verify our current compiler works well, who assures for next version or with
> a different toolchain ? We lose portability.
>
> The change from C++11 to C++14 was here:
> https://cplusplus.github.io/CWG/issues/1806.html
> where they also refer
> https://cplusplus.github.io/CWG/issues/1402.html
> stating that the additional change 1806 was a consequence
> of the resolution for the issue 1402.
> However, 1402 mainly focused on the non-triviality for constructors
> and assignment operators, and THEN also worked on virtual base
> scenarios.
> So, one the one hand, 1402 avoided to uselessly have too many
> cases with deleted move operations, but in my opinion it finally
> led to reach the opposite... too many cases with an implicit definition.
> I am convinced once more that the "unspecified" for move assign.op.
> in case of virtual base classes is dangerous. An alternative should
> be placed in the standard. The simplest: define as deleted.
> Others are possible, but this is matter of discussion.
>
> Mauro.
>
> Il giorno mar 7 lug 2026 alle ore 18:01 Eyal Rozenberg <eyalroz1_at_[hidden]> ha scritto:
>>
>> Hello Mauro and all,
>>
>> I'll first say that I believe the discussion actually stems from a
>> StackOverflow question (I) asked a few days ago about this same subject:
>>
>> https://stackoverflow.com/q/79974174/1593077
>>
>> and the discussion it evoked.
>>
>> Whether that's actually the case or just a coincidence - I believe,
>> Mauro, that the merited specification change is the opposite of what you
>> suggest. AFAICT, the compiler can very well generate a valid
>> move-assignment operator, which moves the virtual base class exactly once.
>>
>> To illustrate this, consider the following 4-class diamond pattern, used
>> also in the SO question:
>>
>> A , with custom move assignment
>> B : public virtual A , with defaulted move-assignment
>> C : public virtual A , with defaulted move-assignment
>> D : public virtual B, public virtual C , with defaulted move-assignment
>>
>> Generating a move assignment for B (resp. C) is obvious: Apply the move
>> assignment of A, then move-assign each of the remaining data members of
>> B (resp. C).
>>
>> Generating a move assignment for _D_ is a little more sophisticated, but
>> still rather straightforward: Given the fact that B and C are defaulted,
>> and the compiler know they comprise of move-assigning A and
>> move-assigning B\A (resp. C\A) - it can generate a move-assignment which
>> does the following:
>>
>> move-assign A
>> move-assign B\A
>> move-assign C\A
>>
>> and Bob's your uncle. The order of B before C is the order of listing of
>> parent classes in the class definition.
>>
>> An SO user at the link raised a concern about consistency with
>> auto-generated copy-assignment; and others claimed that this complicates
>> the language too much, etc. I have not found those arguments very
>> convincing; but of course - I am not well-versed in the standard enough
>> to make a call, and maybe I've missed something. Have I?
>>
>> Eyal
>>
>>
>>
>>
>> On 07/07/2026 11:11, mauro russo via Std-Discussion wrote:
>> > Following the message in
>> > https://lists.isocpp.org/std-discussion/2026/07/3433.php <https://
>> > lists.isocpp.org/std-discussion/2026/07/3433.php>
>> >
>> > I really believe that the behavior from [class.copy.assign]-p(12.3) :
>> > It is unspecified whether subobjects representing virtual base
>> > classes are assigned more than once by the implicitly-defined
>> > copy/move assignment operator
>> >
>> > has room for modification proposals, related to the move assign.op.
>> >
>> > Pls, anyone to clearly state it would not make sense to go
>> > for a step further in https://isocpp.org/std/submit-a-proposal <https://
>> > isocpp.org/std/submit-a-proposal>
>> >
>> > I might propose to go for define as deleted the move assign.op.
>> > as I don't see ways to work around it but not using at all.
>> > Providing an unspecified definition that most likely "clears"
>> > the objects state (moving twice or more), is totally unfair to me.
>> > Other cases of unspecified have a workaround, as for example
>> > the undetermined sequence in arguments evaluation for a
>> > function call -> just don't rely on any in the rest of the code.
>> > But here, I see nothing beyond just not using it.
>> > If not an undefined behaviour, why not being consistent and
>> > include in the rules to define as deleted ?
>> > Other options are possible (to me) but not keep it 'unspecified'.
>> >
>> > Kind regards.
>> > Mauro.
>> >
>>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
<std-discussion_at_[hidden]> napisał(a):
>
> wow, thanks Eyal to highlight it, what a coincidence.
>
> In my case, it came out from standard careful read
> while I was forwarding existing information for an
> internal upskill for colleagues.
>
> That said, let me provide answers to Marcin and you, in turn.
>
> For Marcin:
> > I recall this discussion but was this even in single inhrace case too?
> > And if in this simple case the compiler does multiple moves, could this means
> > that the code created by compiler correctly move all data?
> > Like my example in my prev email, I did multiple moves but as a whole
> > it only "move data" once and does not override it after that.
> > And this idiom can be safely nested as only most outer function
> > have data and rest do empty moves.
>
> I would say, the point is not whether the compiler can do it simply or not
> in special cases. The point is that the standard keeps it "unspecified"
> in any case. To me, it means we cannot use it at all. This links to another
> part of your statement:
> < I did multiple moves but as a whole it only "move data" once
> and does not override it after that >
> First, this would be a contradiction. If the operation is done multiple times,
> then it must move from the source multiple times. Or, at least, the current
> wording from the standard should be clarified. Such a kind of 'final effect
> as if the move happens exactly once' was my hope when I first posted the
> question in https://lists.isocpp.org/std-discussion/2026/07/3430.php
> Pls, note that in https://lists.isocpp.org/std-discussion/2026/07/3431.php
> we had Ville who made this try: https://godbolt.org/z/PK3GEav13
> showing that the move is really performed twice.
> Also, I tried something like this: https://godbolt.org/z/rzq5cq5fK
> (and no problems, instead, with the constructors: https://godbolt.org/z/orMY9xvh5 )
> showing that moving twice destroys the information in both source and
> destination. This means that the compilers implementation are really
> following the standard wording about the option to perform the move
> multiple times.
>
Ok, but all compilers scream that this code is broken, this means
this will not be a sneaky error that unexpectedly hits you.
It looks like compilers simply do not bother to implement this because
how many times you need to move data from polymorphic types?
Usually they are heap allocated and you have only base pointers.
It's a bit hard to move from an object like this.
Probably better indead would be if this was an error than a warning.
But its only needed if the virtual base is duplicated in an object, if it's only
one then there is no problem and we do not need to reject code like that.
> About you, Eyal, I see interesting in the stack overflow thread this information:
> there was a change from C++11 to C++14.
> Before C++14, we had that in case of virtual base classes the move assign.op.
> was defined as deleted, and we had the 'unspecified' only for the copy assign.op.
> In my opinion, this should be reverted. It makes no sense at all to unspecifiy
> for the move, which means we cannot use it at all.
> About the cases when it would be complicated to get or not a "good" implicit
> definition... again, I am not necessarily asking for that. It would be an option,
> but I prefer to have it defined as deleted, simple and consistent.
>
> We are having a hot time for C++ around safety.
> IMHO, having an implicit definition that cannot guarantee at all not to destroy
> the information, means to go against safety.
> No guarantee there means useless. More, it means dangerous, because we
> might have it both implicitly declared and implicitly defined.
> We should not bet by relying that the compiler will do it correctly, at least
> for our simple class. If the standard keeps it unspecified, we risk, and even if
> we verify our current compiler works well, who assures for next version or with
> a different toolchain ? We lose portability.
>
> The change from C++11 to C++14 was here:
> https://cplusplus.github.io/CWG/issues/1806.html
> where they also refer
> https://cplusplus.github.io/CWG/issues/1402.html
> stating that the additional change 1806 was a consequence
> of the resolution for the issue 1402.
> However, 1402 mainly focused on the non-triviality for constructors
> and assignment operators, and THEN also worked on virtual base
> scenarios.
> So, one the one hand, 1402 avoided to uselessly have too many
> cases with deleted move operations, but in my opinion it finally
> led to reach the opposite... too many cases with an implicit definition.
> I am convinced once more that the "unspecified" for move assign.op.
> in case of virtual base classes is dangerous. An alternative should
> be placed in the standard. The simplest: define as deleted.
> Others are possible, but this is matter of discussion.
>
> Mauro.
>
> Il giorno mar 7 lug 2026 alle ore 18:01 Eyal Rozenberg <eyalroz1_at_[hidden]> ha scritto:
>>
>> Hello Mauro and all,
>>
>> I'll first say that I believe the discussion actually stems from a
>> StackOverflow question (I) asked a few days ago about this same subject:
>>
>> https://stackoverflow.com/q/79974174/1593077
>>
>> and the discussion it evoked.
>>
>> Whether that's actually the case or just a coincidence - I believe,
>> Mauro, that the merited specification change is the opposite of what you
>> suggest. AFAICT, the compiler can very well generate a valid
>> move-assignment operator, which moves the virtual base class exactly once.
>>
>> To illustrate this, consider the following 4-class diamond pattern, used
>> also in the SO question:
>>
>> A , with custom move assignment
>> B : public virtual A , with defaulted move-assignment
>> C : public virtual A , with defaulted move-assignment
>> D : public virtual B, public virtual C , with defaulted move-assignment
>>
>> Generating a move assignment for B (resp. C) is obvious: Apply the move
>> assignment of A, then move-assign each of the remaining data members of
>> B (resp. C).
>>
>> Generating a move assignment for _D_ is a little more sophisticated, but
>> still rather straightforward: Given the fact that B and C are defaulted,
>> and the compiler know they comprise of move-assigning A and
>> move-assigning B\A (resp. C\A) - it can generate a move-assignment which
>> does the following:
>>
>> move-assign A
>> move-assign B\A
>> move-assign C\A
>>
>> and Bob's your uncle. The order of B before C is the order of listing of
>> parent classes in the class definition.
>>
>> An SO user at the link raised a concern about consistency with
>> auto-generated copy-assignment; and others claimed that this complicates
>> the language too much, etc. I have not found those arguments very
>> convincing; but of course - I am not well-versed in the standard enough
>> to make a call, and maybe I've missed something. Have I?
>>
>> Eyal
>>
>>
>>
>>
>> On 07/07/2026 11:11, mauro russo via Std-Discussion wrote:
>> > Following the message in
>> > https://lists.isocpp.org/std-discussion/2026/07/3433.php <https://
>> > lists.isocpp.org/std-discussion/2026/07/3433.php>
>> >
>> > I really believe that the behavior from [class.copy.assign]-p(12.3) :
>> > It is unspecified whether subobjects representing virtual base
>> > classes are assigned more than once by the implicitly-defined
>> > copy/move assignment operator
>> >
>> > has room for modification proposals, related to the move assign.op.
>> >
>> > Pls, anyone to clearly state it would not make sense to go
>> > for a step further in https://isocpp.org/std/submit-a-proposal <https://
>> > isocpp.org/std/submit-a-proposal>
>> >
>> > I might propose to go for define as deleted the move assign.op.
>> > as I don't see ways to work around it but not using at all.
>> > Providing an unspecified definition that most likely "clears"
>> > the objects state (moving twice or more), is totally unfair to me.
>> > Other cases of unspecified have a workaround, as for example
>> > the undetermined sequence in arguments evaluation for a
>> > function call -> just don't rely on any in the rest of the code.
>> > But here, I see nothing beyond just not using it.
>> > If not an undefined behaviour, why not being consistent and
>> > include in the rules to define as deleted ?
>> > Other options are possible (to me) but not keep it 'unspecified'.
>> >
>> > Kind regards.
>> > Mauro.
>> >
>>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
Received on 2026-07-09 07:51:06
