移动构造函数
假设我们有这段代码。
class A {
public:
int a;
int b;
A(const A &other) {
this->a = other.a;
this->b = other.b;
}
};
要创建一个复制构造函数,即创建一个复制对象并创建一个新对象的函数,我们通常会选择上面显示的语法,我们将有一个 A 的构造函数,它引用另一个类型为 A 的对象,我们将在方法内手动复制对象。
或者,我们可以编写 A(const A &) = default;
,它会自动复制所有成员,并使用其复制构造函数。
但是,要创建移动构造函数,我们将使用右值引用而不是左值引用,就像这里一样。
class Wallet {
public:
int nrOfDollars;
Wallet() = default; //default ctor
Wallet(Wallet &&other) {
this->nrOfDollars = other.nrOfDollars;
other.nrOfDollars = 0;
}
};
请注意我们将旧值设置为 zero
。默认移动构造函数(Wallet(Wallet&&) = default;
)复制 nrOfDollars
的值,因为它是 POD。
由于移动语义被设计为允许从原始实例窃取状态,因此考虑在此窃取之后原始实例应该是什么样子是很重要的。在这种情况下,如果我们不将值更改为零,我们就会将美元数量增加一倍。
Wallet a;
a.nrOfDollars = 1;
Wallet b (std::move(a)); //calling B(B&& other);
std::cout << a.nrOfDollars << std::endl; //0
std::cout << b.nrOfDollars << std::endl; //1
因此,我们移动构造了一个旧对象。
虽然上面是一个简单的例子,但它显示了移动构造函数的目的。它在更复杂的情况下变得更有用,例如涉及资源管理时。
// Manages operations involving a specified type.
// Owns a helper on the heap, and one in its memory (presumably on the stack).
// Both helpers are DefaultConstructible, CopyConstructible, and MoveConstructible.
template<typename T,
template<typename> typename HeapHelper,
template<typename> typename StackHelper>
class OperationsManager {
using MyType = OperationsManager<T, HeapHelper, StackHelper>;
HeapHelper<T>* h_helper;
StackHelper<T> s_helper;
// ...
public:
// Default constructor & Rule of Five.
OperationsManager() : h_helper(new HeapHelper<T>) {}
OperationsManager(const MyType& other)
: h_helper(new HeapHelper<T>(*other.h_helper)), s_helper(other.s_helper) {}
MyType& operator=(MyType copy) {
swap(*this, copy);
return *this;
}
~OperationsManager() {
if (h_helper) { delete h_helper; }
}
// Move constructor (without swap()).
// Takes other's HeapHelper<T>*.
// Takes other's StackHelper<T>, by forcing the use of StackHelper<T>'s move constructor.
// Replaces other's HeapHelper<T>* with nullptr, to keep other from deleting our shiny
// new helper when it's destroyed.
OperationsManager(MyType&& other) noexcept
: h_helper(other.h_helper),
s_helper(std::move(other.s_helper)) {
other.h_helper = nullptr;
}
// Move constructor (with swap()).
// Places our members in the condition we want other's to be in, then switches members
// with other.
// OperationsManager(MyType&& other) noexcept : h_helper(nullptr) {
// swap(*this, other);
// }
// Copy/move helper.
friend void swap(MyType& left, MyType& right) noexcept {
std::swap(left.h_helper, right.h_helper);
std::swap(left.s_helper, right.s_helper);
}
};