SebastienBini / cpp-relocation-proposal

C++ standard proposal for Relocation
0 stars 1 forks source link

Decomposing relocation constructor #36

Open SebastienBini opened 1 year ago

SebastienBini commented 1 year ago

Now that we have decomposing functions, and that D2839R1 achieves its relocation constructor with authorizing reloc in ctor-initializer, I think we can do better than what we are currently proposing.

What if the relocation constructor could act as a decomposing function with regards to its source object? Right before entering the ctor-initializer, the source is decomposed into individual objects for each direct base and non-static data member. They live for the duration of the ctor-initializer, and if they are not relocated, they are otherwise destroyed in reversed declaration order.

class T : public B
{
public:
  T(T reloc) : /* starts lifetime of "B", _d1, _d2 and _d3 */
    B{reloc B}, _d1{reloc _d1}, _d2{this->_d1}
    /* _d3 and _d2 are destroyed, in that order */
  {}

private:
  D1 _d1;
  D2 _d2;
  D3 _d3;
};

We could even go as far as allowing delegating constructors with this approach:

class T : public B
{
public:
  T(T src) : T(reloc src, std::lock_guard{some_mutex}) {}

private:
  T(T reloc, std::lock_guard<std::mutex>) : /* starts lifetime of "B", _d1, _d2 and _d3 */
     B{reloc B}, _d1{reloc _d1}, _d2{this->_d1}
    /* _d3 and _d2 are destroyed, in that order */
    {}

private:
  D1 _d1;
  D2 _d2;
  D3 _d3;
};

The relocation constructor as currently proposed can stay. I believe the delegating ctor case is a motivating example of why we need both. This decomposing relocation constructor would only be reserved if the source object is named reloc. This allows us to write a second relocation ctor (like the private ctor of T) which benefits from the decomposition trait.

In the example, we might infinitely call the relocation constructor when building the first parameter of the private constructor. I believe the compiler must now that there exists an elided version of that private ctor so that it needn't call the relocation ctor again until it blows up the stack :/ Hence reloc must appear in the declaration of that second ctor. This should be okay as we cannot take the address of a constructor. However it feels a bit off that the name of a parameter changes the ABI, so maybe we should allow, for relocation constructors only, reloc T as well as T reloc: T(reloc T, std::lock_guard<std::mutex>) : ....

And... what about decomposing relocation assignment operator? I think they should be allowed if decomposing relocation ctors are a thing. I have not much to say about them though, no particular issue comes to mind.

SebastienBini commented 10 months ago

This conflicts with the approach raised in issue #38 Delegating relocation constructors are not supported with issue #38