Date: Wed, 23 Aug 2023 09:03:10 -0800
On Wed, Aug 23, 2023 at 8:01 AM Breno Guimarães <brenorg_at_[hidden]> wrote:
> Perhaps a fair addition to the language is to allow RVO with slicing iff
> sizeof(Base) == sizeof(Derived):
>
> struct LockedMutex : public std::mutex {
> LockedMutex() { lock(); }
> };
>
> std::mutex getLockedMutex() { return LockedMutex(); } // Hey, why not?
>
You'd have to explain whose destructor that code runs, and why.
struct Animal { ~Animal(); };
struct Cat : Animal { ~Cat(); };
Animal getAnimal() { Cat c; return c; }
int main() { Animal a = getAnimal(); }
Today this calls Cat(), Animal(Cat&&), ~Cat(), ~Animal().
I think you're proposing it would run Cat(), ~Animal(). Which is mismatched.
Or else this particular variation wouldn't compile — maybe we say "okay, in
order to trigger the feature we must have sizeof(Base) == sizeof(Derived)
*and* Derived has no non-defaulted destructor, and Derived has no
non-inherited data members, and Derived has no direct bases other than
Base, ..." But that's epicycles on top of epicycles, which is never a good
sign. And even once the physical stuff works, we'll still have to explain
to the object model why it's okay to construct a Cat and destroy only an
Animal. (Admittedly the object model already has trouble with NRVO, so
maybe this doesn't really make it worse. But it certainly doesn't *help*.)
("... and Derived is not polymorphic; and overload resolution on
Base(Derived&&) finds some move constructor of Base, not anything else ...")
I'd rather have a feature designed to play well with the object model (a
feature that lets me somehow "run code on a prvalue-in-flight", or simply
mark a return statement to "force NRVO") than a physical hack like that.
(And I think the majority of EWG would agree, if such a hack ever actually
reached a vote: I think ultimately it wouldn't stand any real chance.)
my $.02,
–Arthur
> Perhaps a fair addition to the language is to allow RVO with slicing iff
> sizeof(Base) == sizeof(Derived):
>
> struct LockedMutex : public std::mutex {
> LockedMutex() { lock(); }
> };
>
> std::mutex getLockedMutex() { return LockedMutex(); } // Hey, why not?
>
You'd have to explain whose destructor that code runs, and why.
struct Animal { ~Animal(); };
struct Cat : Animal { ~Cat(); };
Animal getAnimal() { Cat c; return c; }
int main() { Animal a = getAnimal(); }
Today this calls Cat(), Animal(Cat&&), ~Cat(), ~Animal().
I think you're proposing it would run Cat(), ~Animal(). Which is mismatched.
Or else this particular variation wouldn't compile — maybe we say "okay, in
order to trigger the feature we must have sizeof(Base) == sizeof(Derived)
*and* Derived has no non-defaulted destructor, and Derived has no
non-inherited data members, and Derived has no direct bases other than
Base, ..." But that's epicycles on top of epicycles, which is never a good
sign. And even once the physical stuff works, we'll still have to explain
to the object model why it's okay to construct a Cat and destroy only an
Animal. (Admittedly the object model already has trouble with NRVO, so
maybe this doesn't really make it worse. But it certainly doesn't *help*.)
("... and Derived is not polymorphic; and overload resolution on
Base(Derived&&) finds some move constructor of Base, not anything else ...")
I'd rather have a feature designed to play well with the object model (a
feature that lets me somehow "run code on a prvalue-in-flight", or simply
mark a return statement to "force NRVO") than a physical hack like that.
(And I think the majority of EWG would agree, if such a hack ever actually
reached a vote: I think ultimately it wouldn't stand any real chance.)
my $.02,
–Arthur
Received on 2023-08-23 17:03:23