C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relocation in C++

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Mon, 2 May 2022 14:54:03 +0100
On Mon, 2 May 2022 at 14:23, S├ębastien Bini <sebastien.bini_at_[hidden]>
wrote:

> > A destructor may call arbitrary methods on the class under destruction,
> > which will have no way to tell that the instance they are invoked on was
> > previously relocated. How will you ensure safety in this scenario? It
> seems
> > that there will be a considerable burden on the class author to ensure
> that
> > all methods called from the destructor are safe to be called on a
> relocated
> > instance, since the language will not ensure this, and a considerable
> > maintenance burden going forward.
>
> I don't see how that's different from the destructor call on a moved
> instance.
>

Here you're explicitly adding another state to the object for the (original
and subsequent) authors to have to keep track of. Currently an object (e.g.
a container) has: - default (empty) state; - value-containing state; -
moved-from state (usually the same as empty state). Adding a relocated
state means more work and more potential bugs. If instead relocation
destroys the object then there are no additional states and quite often
fewer,; the moved-from state can be made the same as the empty state, since
there is no need for a singular moved-from state.

In fact the first version of the paper worked this way: the relocation
> destructor acted as a constructor for the new instance and as a destructor
> for the relocated instance. As such, the destructor of the relocated
> instance was not called, as the instance was already considered destructed.
>
> However, as others have pointed it out, this leads to an ABI break.
> Consider:
>
> void sink(T z);
>
> void fwd_to_sink(T y)
> {
> sink(reloc y); // oops
> }
>
> void foo()
> {
> T x;
> fwd_to_sink(reloc x);
> }
>
> In fwd_to_sink, reloc cannot omit the call to the destructor of 'y', as it
> is called by 'foo'. For this to work:
> - fwd_to_sink would need to somehow return some information on the
> destruction state of its parameters.
> - or change the call convention so that the parameters are destructed in
> the called function body instead of the callee site.
>

Yes, I recognize the issue. This can be resolved by stating that
implementations may refuse to relocate function parameters, and providing a
mechanism (e.g. an attribute) for the author to switch ABI to
callee-destroy.

I thought of something similar:
> struct T {
> operator reloc(); // return a new instance of T, like a constructor
> would do
> // or as a static variant with signature:
> operator reloc(T&& self);
> };
>
> But I found it very inconvenient to write the function body:
>
> struct T : public B {
> operator reloc() {
> // how to construct the B part of T into the new T using B's reloc?
> // how to initialise the data-members of T using the reloc
> }
> }
>
> This can hardly reuse the constructor syntax (with base class and
> data-member initialisers). I couldn't find anything convincing in that
> path, but I can still give it more thought.
>

Yes, this is a bit tricky (base classes in particular), though I have some
ideas about possible syntaxes. However, much of the time `= default` will
be sufficient, and in the remainder it may be acceptable to treat the
source object as an xvalue, on the proviso that it will be immediately
destructed. In other words I'm not convinced that this will be a problem in
practice; some examples of classes that would need a user-provided
relocation operation might help.

Received on 2022-05-02 13:54:15