C++ Logo

std-discussion

Advanced search

Re: unspecified defaulted move assignment with virtual bases

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Tue, 7 Jul 2026 16:41:05 +0200
wt., 7 lip 2026 o 16:33 mauro russo <ing.russomauro_at_[hidden]> napisał(a):
>
> Marcin,
>
> just to be clear. I have not yet an established proposal.
>
> My main concern is whether we should discuss here or to go for a paper
> according to the process in https://isocpp.org/std/submit-a-proposal ,
>
> Going back to your example:
>
> struct Foo
> {
> };
> struct Bar : virtual Foo
> {
> };
>
> int main()
> {
> Bar b;
> b = Bar{};
> }
>
> this can be quite simple for the compiler to perform one
> operation only.
> Consider also the contribute from Ville in
> https://lists.isocpp.org/std-discussion/2026/07/3431.php
> with a case where both gcc and clang apply the operation twice,
> just as effect of simple implicit implementation.
>
> My main concern is still that "unspecified" seems a bad choice
> for the move assignment operator. It allows to get a counter-intuitive
> effect that may lead to undefined behavior when later the assigned
> object is used. And I see no workaround but not using the move
> assignment at all.
>

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.

> Possible alternatives in a future proposal:
>
> Easy alternative: always define as deleted when there are virtual bases.
> This would be more portable.
>
> Intermediate alternative: let the compiler choose whether it is able
> to manage (case by case). In such alternative it might be unspecified
> when the compiler is able to apply the operation just once per each virtual
> base, but if not then the move assign.op. would be defined as deleted.
> In this case, it would be unspecified to get a fallback to copy or not,
> but no risk to go under bad behavior.
>
> Complex alternative: to fix rules when the compiler should provide
> a "good" implicit definition (e.g., for simple cases as in your example)
> instead of defining as deleted.
> I am not passionate for this alternative, but others might prefer it.
> I see in general that the rules to lead defaulted special member
> functions to be defined as deleted are designed to be simple,
> and so this alternative should be discarded.
>
> However, again, it's quite early to discuss the preferrable alternative now.
> My concern now remains: "unspecified" as it is now appears bad to me.
>
> Is there any serious motivation to say "no, unspecified is totally fair"
> and stop my effort here ?
>
> Thanks,
> Mauro.
>
>
> Il giorno mar 7 lug 2026 alle ore 15:17 Marcin Jaczewski <marcinjaczewski86_at_[hidden]> ha scritto:
>>
>> wt., 7 lip 2026 o 14:42 mauro russo <ing.russomauro_at_[hidden]> napisał(a):
>> >
>> > hello Marcin,
>> >
>> > thanks for the interest.
>> >
>> > No, I never stated I am interested to make it 'defined' with the guarantee
>> > of a single action on each virtual base.
>> > Indeed, my proposal would likely be to go for 'defined as deleted'.
>> >
>>
>> Ok, this makes sense.
>> This will apply to all cases? Like:
>>
>> ```
>> struct Foo
>> {
>> };
>> struct Bar : virtual Foo
>> {
>> };
>>
>> int main()
>> {
>> Bar b;
>> b = Bar{};
>> }
>> ```
>>
>> This code will be lagal after your change?
>> I think we could still allow it and only ban hard cases.
>>
>>
>> Overall only way for user to have move operation on type like this is:
>> ```
>> VirtualBase temp = std::move(*(VirtualBase*)&other);
>> *(BaseA*)this = std::move(*(BaseA*)&other); //move empty `VirtualBase`
>> *(BaseB*)this = std::move(*(BaseB*)&other); //move empty `VirtualBase`
>> *(VirtualBase*)this = std::move(temp);
>> ```
>> This add lot of new moves there but at least final values will be preserved.
>> Another problem is a lot of typing and boilerplate.
>>
>> > The main concern currently is that the standard indicates it
>> > as 'unspecified', with a big danger in using it.
>> > Since I see no way to work around it but not using it
>> > at all, then why keeping it unspecified for move assign.op. ?
>> >
>> >
>> > Il giorno mar 7 lug 2026 alle ore 11:21 Marcin Jaczewski <marcinjaczewski86_at_[hidden]> ha scritto:
>> >>
>> >> Question is if it's possible to make it defined? and at what cost?
>> >>
>> >> As each middle base class move assignment function do not know if the
>> >> current object is the only "owner"
>> >> of this virtual base object or not. In theory the constructor of the
>> >> current object knowed this but it's still available after that?
>> >>
>> >> Another thing is that is this possible without breaking ABI?
>> >>
>> >> wt., 7 lip 2026 o 10:11 mauro russo via Std-Discussion
>> >> <std-discussion_at_[hidden]> napisał(a):
>> >> >
>> >> > Following the message in
>> >> > 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
>> >> >
>> >> > 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-07 14:41:20