2

I'm trying to get the deep knowledge about how should I write my copy and move constructors and assignment operators.

In Bjarne Stroustrup's "The C++ Programming Language - 2013" I see the following example of move constructor and move assignment:

template<class T, class A>
vector_base<T,A>::vector_base(vector_base&& a)
   : alloc{a.alloc},
   elem{a.elem},
   space{a.space},
   last{a.space}
{
   a.elem = a.space = a.last = nullptr; // no longer owns any memory
}

template<class T, class A>
vector_base<T,A>::& vector_base<T,A>::operator=(vector_base&& a)
{
   swap(∗this,a);
   return *this;
}

(Side note: there seems to be a typo in the book: ::& should be just &, right?)

I suspected it should cause endless recursion, since std::swap() calls move assignment operator:

template<typename T>
void swap(T& lhs, T& rhs)
{
  auto temp(lhs);
  lhs = std::move(rhs);
  rhs = std::move(temp);
}

I've checked it, here's very simple program:

#include <iostream>
using namespace std;

class TestA {
   int x;

public:
   TestA(int x = 0) : x(x) {
      cout << "TestA value ctor " << x << "\n";
   }

   ~TestA() {
      cout << "TestA dtor " << x << "\n";
   }

   TestA(const TestA &a) : x(a.x) {
      cout << "TestA copy ctor " << x << "\n";
   }

   TestA(TestA &&a) : x(a.x) {
      cout << "TestA move ctor " << x << "\n";
   }

   TestA operator=(const TestA &a) {
      x = a.getX();
      cout << "TestA copy assignment " << x << " = " << a.getX() << "\n";
      return *this;
   }

   TestA &operator=(TestA &&a) {
      cout << "TestA move assignment " << x << " = " << a.getX() << "\n";
      swap(*this, a);
      return *this;
   }

   int getX() const {
      return this->x;
   }

};

int main(void) {
   TestA a{0};
   TestA b{1};
   {
      TestA c{2};
      a = move(c);
   }
}

Which produces the following output, so I was right about endless recursion:

TestA value ctor 0
TestA value ctor 1
TestA value ctor 2
TestA move assignment 0 = 2
TestA move ctor 0
TestA move assignment 0 = 2
TestA move ctor 0
TestA move assignment 0 = 2
TestA move ctor 0
...
...

Do I miss something? How can I use swap() inside move assignment?

Dmitry Frank
  • 10,417
  • 10
  • 64
  • 114

2 Answers2

6

You're not missing anything, and the accepted answer is wrong. Stroustrup's book is simply bad. There is no free-standing swap() anywhere in chapter 13; it's strongly implied that this swap() is std::swap() (just like copy() is std::copy(), etc.). It's just a bug. Welcome to C++.

Evg
  • 25,259
  • 5
  • 41
  • 83
VicTheHack
  • 61
  • 1
  • 1
4

What you are missing is that Stroustroup provides a free-function swap(TestA&, TestA&) in the same namespace as the class.

Also, he does not call it as std::swap (neither does your code), but uses an unqualified id and injection of std::swap into the namespace with using ::std::swap;.

Which means the generic version provided by the standard is not used.

At least that is how it should be. Seems that free-standing swap() is really missing. Ouch.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Thanks, it sounds true, but I've just tried to find that free-function `swap()` in my pdf book file, and I failed to find it. Is it so obvious so that it doesn't even worth mentioning? :) – Dmitry Frank Mar 06 '15 at 21:49
  • 1
    Does the code in the book actually take the argument as `vector_base&&` in the assignment operator? The copy and swap idiom usually uses a value parameter. – David G Mar 06 '15 at 21:50
  • @0x499602D2, yes, of course I've just copy-pasted the code. It's on page 379, section 13.6.2. – Dmitry Frank Mar 06 '15 at 21:51
  • It should be somewhere in the book. I cannot verify it though, haven't got it. – Deduplicator Mar 06 '15 at 21:53
  • @0x499602D2 It's not copy and swap. It's just using swap to implement move assignment, which is perfectly valid (assuming a specialized swap, of course). – T.C. Mar 06 '15 at 21:58
  • @T.C. Yeah I figured that. Thanks. – David G Mar 06 '15 at 22:00
  • 1
    @Deduplicator, just fyi: it is not, at least I and my pdf viewer failed to find it. Thanks for your answer, again. – Dmitry Frank Mar 07 '15 at 12:35
  • I'm looking for this same std::swap and it's not there, not even on the errata on Stroustrup's website. Odd. – Martin Jun 28 '20 at 00:26