C++ Logo

std-discussion

Advanced search

Re: unspecified defaulted move assignment with virtual bases

From: mauro russo <ing.russomauro_at_[hidden]>
Date: Thu, 9 Jul 2026 18:46:52 +0200
Hi Marcin,

so, you state that the compilers already provide a warning, and then you
propose to get an error, instead, except when virtuale base is present once
in the hierarchy. You also argue that the move assignment for such a kind
of polymorphic types is likely never used.

What I see here is that you are mixing a bit the roles, between standard
and compilers.
The standard drives the rules, and the compilers (try to) match such rules
(sometimes with proper extensions).
Even if in practice there is a certain interaction between standard editors
and compiler implementors, it does not mean that roles can be inverted.

The fact that here the compilers get a warning, represents to me once more
a confirmation that the rule itself has something wrong, and the compiler
designers would probably like to stop with an error, but they cannot (if
they want to remain standard-compliant on this).

Even the fact that such an assignment is likely never used, is once more an
argument to require for having it deleted.
If such a simple rule seems too strong and you would like to keep a
definition for simple cases where it works fine, that would be matter of
discussion after having established that some change is anyway needed in
the standard.
Currently, the standard allows/pushes the compilers to implictly define
something seriously dangerous and this is the main concern. It shouldn't.



Il gio 9 lug 2026, 09:51 Marcin Jaczewski <marcinjaczewski86_at_[hidden]> ha
scritto:

> ś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
>

Received on 2026-07-09 16:47:13