问题
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?
回答1:
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.
回答2:
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++.
来源:https://stackoverflow.com/questions/28908004/usage-of-stdswap-inside-move-assignment-should-cause-endless-recursion-and