0

The question is basically the same as the old Why aren't there compiler-generated swap() methods in C++0x?, but provides more recent context and asks for a more up-to-date answer.

If for some class C swap(C&, C&) is implemented much more efficiently than std::swap<C>, then each class D that contains C as a data member or inherits C must define its own swap(D&, D&) in order to benefit from swap(C&, C&)'s efficiency (std::swap<D> only calls D's move constructor and move assignment operator, which in turn call C's move operations). Then each class that contains a D data member or inherits D has to implement its own swap() for maximum efficiency, and so on.

The top answer to Move semantics == custom swap function obsolete? states that a custom swap() can often be much faster. But writing even a trivial custom definition is error-prone: each base class and each data member has to be swapped; each newly-added base class or data member requires a modification of the custom swap()'s definition.

n3746 proposes adding a new operator to replace the free swap() function. The proposal has been rejected because the committee felt that already implemented swap() overloads would be retained and called by new code for backwards compatibility. The coexistence of the swap operator and the free swap() function is considered undesirable. But is there a reason why the free friend swap() function cannot be implicitly generated or declared by the user as defaulted? For example:

class D : public Base
{
public:
    friend void swap(D&, D&) = default;
private:
    C c_;
    std::vector<int> v_;
    double r_;
};

The compiler could generate the following definition:

void swap(D& a, D& b) noexcept(...)
{
    using std::swap;
    swap(static_cast<Base&>(a), static_cast<Base&>(b));
    swap(a.c_, b.c_);
    swap(a.v_, b.v_);
    swap(a.r_, b.r_);
}

Here noexcept(...) stands for noexcept(true) if swapping each subobject is noexcept(true); noexcept(false) otherwise.

The compiler could implicitly declare and generate swap() for a class that has no user-declared copy/move constructor/assignment operators. This is somewhat risky due to the absence of std::swap()'s strong exception guarantee. But the implicitly-generated copy and move special members lack strong exception guarantee too, so this shouldn't be much of a problem.

The compiler-generated swap() would get rid of error-prone custom boilerplate definitions and speed up swapping objects of classes and structs, for which no custom swap() is implemented. Is there a technical or a philosophical reason why this feature hasn't been proposed for the C++ standard? Is the feature relatively unimportant? Or is this an oversight/omission?

vedg
  • 785
  • 2
  • 7
  • 18
  • The proposal for swap already covers the case where move semantics (move constructors) is directly used in std::swap so an extra constructor is not really needed. Personally I think having std::swap is good enough and in code it clearly shows your intent which I think is also important. Also getting a proposal to extend stl or the language accepted needs a lot of detail and work, check http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm and you can see how much detail is involved in "simple" swapping – Pepijn Kramer Sep 18 '21 at 11:06
  • Sure, `std::swap` is good enough for some types, but not for types `C` that have expensive move constructors (e.g. if each object always contains allocated data as an invariant), and consequently not for types that contain `C` as a subobject. The implicit/defaulted `swap()` is an addition rather than a replacement for `std::swap`, and I think it shows one's intent as clearly as `std::swap` does. – vedg Sep 18 '21 at 11:51
  • If it would be compiler generated, then I think that it should be deleted if any sub object swap would throw. – Phil1970 Sep 18 '21 at 12:58

0 Answers0