C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relocating destructor and operator reloc

From: 江岸 <de34_at_[hidden]>
Date: Sat, 29 Jun 2024 15:03:32 UTC
Yeah. FWIW, reconstruction is generally problematic for potentially-overlapping subobjects.

Thanks,
F.v.S.
在 Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]>,2024年6月29日 22:06写道:

On Fri, Jun 28, 2024 at 11:31 AM 李 秋逸 via Std-Proposals <std-proposals_at_[hidden]> wrote:
Sorry for bother you. Seeing some proposals about relocating in C++, I think I found a easy and flexible way to do this with least changes to the core feature of C++ language. You can check it in the attachment or click https://github.com/YandereChan2/Relocating-destructor-and-operator-reloc/blob/main/Operator%20reloc%20and%20relocating%20destructor.md .
The core idea is introduce a new destructor T ~T(int), and with the help of RVO/NRVO to relocate an object from one address to the address of the return value.

Section 4 is conspicuously missing any example of a class with a non-trivial data member and a non-trivial relocating destructor.
Of course programmers should avoid writing any such type, as a stylistic preference; but you need to explain how it would work.

    struct S {
        ~S();
        S ~S(int);
    };

    struct Composite {
        S s_;
        int *p_;
        Composite(int *p) : s_(), p_(p) {}
        Composite(Composite&& rhs) : s_(std::move(rhs.s_)), p_(std::exchange(rhs.p_, nullptr)) {}
        Composite& operator=(Composite&& rhs) { s_ = std::move(rhs.s_); p_ = std::exchange(rhs.p_, nullptr); return *this; }
        ~Composite() { delete p_; }

        Composite ~Composite(int) {
            Composite copy = std::move(*this);  // How do I work `reloc(this->s_)` into this code?
            return copy;  // I don't want s_'s destructor to run here, because I've already relocated out of it; but p_'s (trivial) destructor needs to run as usual.
        }
    };

In writing this example, it also occurred to me that your syntax `NameOfType ~NameOfType(int)` is pretty repetitive.
P2952 (to be seen by EWG sometime in the next ~6 months) might help you here, but maybe this is also a sign that you should look for a simpler syntax.

What happens if I write some other type there?
    std::any ~MyType(int) { ~~~~ }  // Relocate myself into a std::any?
This is the first corollary to Murphy's Law: If you don't want people writing that, then maybe you should find a syntax that makes it impossible to write that. (See also "Make invalid states unrepresentable".)

A hot topic right now is whether trivial relocation can be used for swap. (P2786 says "no"; P1144 says "yes"; most industry code says "of course yes"; and you assume the answer is "yes" as well.) For P1144, this isn't a problem, because obviously if an object's value follows its object representation, then you can by definition swap two values by swapping their object representations — and P1144 defines "trivially relocatable" as a holistic property (analogous to "trivially copyable") specifically meaning that an object's value follows its object representation. So there's no problem with std::swap in P1144.
(Now, P1144 does leave the implementation of "swapping object representations" up to the STL implementation. Everyone just uses either `memcpy` or `__builtin_memcpy` to copy object representations today, e.g. inside std::copy, even for non-TC types. Compiler vendors are technically allowed to add more ceremony around copying object representations, and force STL vendors to use those ceremonies — but thankfully no compiler vendor has felt the desire to do so, yet.)

But in your proposal for non-trivial relocation, you aren't just swapping object representations in an unspecified vendor-specific manner. The only way you can relocate an object's value is by calling its relocating destructor, which by definition destroys the object. So when you propose that std::swap(a,b) should use relocation, you're proposing that std::swap(a,b) should destroy both a and b and then re-construct them. So the `a` object that exists after a swap isn't the same `a` object that existed before the swap. Not just "same object with different value," but literally it is now a different object. That's the same problem that P2786 has with swap — except that whereas P2786 says "okay, so we can't optimize swap for TR types," you just seem to be ignoring the problem. You'll have to tackle it head-on, because right now it looks like a complete roadblock for your proposal.

my $.02,
Arthur

Received on 2024-06-29 15:03:44