-1

I have implemented a swap method for my class that inherits from enable_shared_from_this<...>

class X : public enable_shared_from_this<X> {
    int x;
    friend void swap(X& x1, X& x2) {
        using std::swap;
        swap(x1.x, x2.x);
    }
    X& operator=(X other) {
       swap(*this, other);
    }
    ...
}

I tried to swap the enable_shared_from_this<...> part in the swap method by adding either:

std::enable_shared_from_this<X>::swap(first, second);

Doesn't compile because of:

No member named 'swap' in 'std::enable_shared_from_this'

swap(static_cast<std::enable_shared_from_this<X>>(first), static_cast<std::enable_shared_from_this<X>>(second));

Doesn't compile because of:

Calling a protected constructor of class 'std::enable_shared_from_this' protected constructor can only be used to construct a base class subobject

Finally I resorted to adding the following line in the assignment operator:

std::enable_shared_from_this<X>::operator=(other);

But this feels wrong to me because the swap method is incomplete and in general mixing two idioms (I guess).

So what is the correct way to handle this...?

Note: I'm using C++20.

traveh
  • 2,700
  • 3
  • 27
  • 44

1 Answers1

2

enable_shared_from_this technically has a copy constructor and assignment operator. But they don't meaningfully work. Neither of them copies the weak_this internal member. So even after assignment, the weak_this will be the same.

Swapping is not functionality that enable_shared_from_this supports.

Note that swapping them wouldn't actually make sense. The shared_ptrs managing the memory for each object point to the specific objects they manage. Swapping objects only swaps their contents; the address of the two objects remains the same. So the managed storage should still refer to the original objects because their addresses didn't change.

As such, it makes sense that you cannot "copy" or "swap" enable_shared_from_this. So just leave the base class subobjects alone.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • This makes sense to me if my shared pointers share the same resource for all objects of this class, but in my case the shared pointers do not (necessarily) do that... (in the case the object is copied/moved/assigned they should be the same, but not necessarily when I want to swap them... in fact, my case is a bit more complicated with multiple virtual inheritance but I *think* that part is not related... if it is I'll post another question with more details...) – traveh Oct 20 '22 at 15:45
  • What you said doesn't make sense. You have two objects, A and B. Each of them has a separate shared state. That shared state contains the *addresses* of A and B. If you swap the contents of A and B... their addresses *do not change*. Even if logically A now has the contents and behavior of the old B, it is still *object A* and *not* object B. It does not *become* B; it merely contains B's old data. The shared states still point to A and not B. – Nicol Bolas Oct 20 '22 at 15:49
  • @traveh: You cannot change the pointers being managed by the shared states themselves. They aren't even part of `enable_shared_from_this`. – Nicol Bolas Oct 20 '22 at 15:49
  • @traveh: "*my case is a bit more complicated with multiple virtual inheritance*" Irrelevant. You cannot logically swap objects of different types. I mean, you can make it technically work, but you've stepped far out of the domain of what "swap" is supposed to actually mean. – Nicol Bolas Oct 20 '22 at 15:51
  • Oh I think I understand... but what if one of them is actually empty (i.e. nullptr)...? In this case I'm supposed to fill it with an empty state and swap the empty state's contents with the other one? – traveh Oct 20 '22 at 16:04