Hi all,

> Right, I think there's a mismatch between the way Avi was using/understanding the terminology and the way you (and I) use it.

Yes, I've seen this confusion a few times (I don't know if that's the case here). We do need to carefully pick our words :p

> {
> std::string src1 = "hello world";
> std::string dst1 = std::relocate(src1);
> std::string src2 = "hello world";
> std::string *dstp = ~~~~;
> ::new ((void*)dstp) std::string(std::relocate(src2));
> ~~~~
> } // Here dst1.~string() is implicitly called, as are src1.~string() and src2.~string().
> // But src1 and src2 were already destroyed, so that's a double-free bug and Bad Stuff happens.
> // P1144 doesn't try to solve this part; it just claims you shouldn't be doing that.

The reloc operator allows for all that except it would be perfectly safe (no double destructor call):

    std::string src1 = "hello world";
    std::string dst1 = reloc src1;
    std::string src2 = "hello world";
    std::string *dstp = /* some uninitialized memory address */;
    reloc ((void*)dstp) std::string(src2); /* there is a "placement reloc" variant that is proposed as well */

> Yes, it's unfortunate, but the alternatives (not being able to reloc function parameters at all, or breaking relocate-only types) are worse.

In my opinion, if we are to support relocatable-only types, then we need to provide some way to:
1. relocate local objects (be it function parameter or not)
2. relocate an existing object inside a container
3. relocate an object out of a container (that one should be easy with std::relocate_at)

> You can't relocate function parameters, but it's viable to relocate *constructor* parameters, since constructors don't have types. So optional can have an additional constructor taking its prvalue argument by callee-destroy; this won't require new kinds of function pointer since you can't form a function pointer to a constructor.

I agree that constructor prvalue parameters could be relocated, since constructors are kind of special. But still there must be some way to indicate that this constructor must have that special ABI.

> You'll need a relocate_wrapper type that can be (possibly implicitly) constructed from a callee-destroy prvalue, and that releases that value (by relocation to a prvalue) on request. So you call either push_back(relocate_wrapper(reloc x)), or relocate_back(reloc x).

This is similar to what is in the proposal: std::reloc_wrapper (page 24, https://github.com/SebastienBini/cpp-relocation-proposal/blob/main/relocation.pdf). You can relocate an object inside it, check if it has an object, and relocate it out. The problem is then that you need to perform two relocations (one inside the wrapper, one from the wrapper to the container).

In my proposal, I suggested push_back overloads that took a tag type as first parameter and a prvalue as second: std::vector<T>::push_back(std::relocate_t, T);

The std::reloc_wrapper of my proposal was introduced mainly for std::pair and std::tuple, where a ctor API with std::relocate_t tag type would be confusing, and that those types (pair and tuples) already know how to unwrap std::reference_wrapper.

I also would like to point out that the second revision of the proposal already allows for all three points I mentioned above (to support relocatable-only types), with no new ABI, and no special wrapper for most uses. And this remains possible because reloc does not destruct objects (which is a downside I admit). I am just reminding you this because at some point we need to decide between the two options: (a) non-destructive relocation, but easier to handle, or (b) destructive relocation but at the cost of more complexity.

> But std::relocate_at is a Standard library function. It doesn't need to be implementable; you just write language that says what its effects are, the actual implementation will just call a compiler builtin. Even in the trivial case you don't want to call memcpy, since you want it usable in constexpr.

That's a fair point. Also, if no one sees a point of having non-default base-or-member initialisers in operator reloc member function, and that its source object is already destructed once the function body is reached, what would be wrong with this operator reloc?

struct T : B
{
    M data;

    /*
     * operator reloc returns a new instance.
     * actual relocation (base-class and data-member relocations) happen before the function body is called (as if by =default).
     * The function body only serves to make some adjustments, like fixing self-references.
     * 'this' pointer in reloc function body points to the newly constructed instance.
     * The source object is considered destructed and is no longer usable, that's why it does not appear as a parameter.
     * It is not possible to provide custom base-or-member-initializer.
     */
    operator reloc()
    {
        data.self = *this; // fix self-references here
    }
};