如果你还不了解左值和右值,可以看 cpp中的lvalue和rvalue
我直接放代码了
#include <iostream>
#include <string>
void print(const std::string& str) {
std::cout << str << std::endl;;
}
// 先写一个很蠢的string类,只是为了演示
class String {
private:
char* data_;
size_t size_;
public:
String(const char* str) {
print("default constructor of String");
size_ = strlen(str);
data_ = new char[size_];
memcpy(data_, str, size_);
}
String(const String& other) {
print("copy constructor of String");
size_ = other.size_;
data_ = new char[size_];
memcpy(data_, other.data_, size_);
}
String(String&& other) noexcept {
print("move constructor of String");
//我们在这里偷走了other的资源。
size_ = other.size_;
data_ = other.data_;
other.data_ = nullptr;
other.size_ = 0;
}
~String() {
print("Destroy String!");
delete data_;
}
void Print() const {
for (int i = 0;i < size_; i++)
printf("%c", data_[i]);
}
};
class A {
private:
String a;
public:
A(const String& str):a(str) {
print("default constructor of A");
}
// 如果不在这里做这个看似很蠢的cast,那么String的拷贝构造函数仍然会被调用。
A(String&& str):a(static_cast<String&&>(str)) {
print("move string constructor of A");
}
};
int main(int argc, char* argv[]) {
A a(String("test"));
return 0;
/*
* output:
* default constructor of String
* move constructor of String
* move string constructor of A
* Destroy String!
* Destroy String!
*/
}
= and std::move
还记得吗,上一段中我们写了类似 static_cast<String&&>(str) 这样的东西,更优雅的方式是使用 std::move(), 不仅优雅哈哈而且还更容易理解。
最后,如果我们实现了下面这个函数
String& operator=(String&& other) noexcept {
print("move constructor of String");
//我们在这里偷走了other的资源。
if (this != other) {//如果两个东西是同一个东西,就没必要做任何操作了
delete[] data_;
size_ = other.size_;
data_ = other.data_;
other.data_ = nullptr;
other.size_ = 0;
}
return *this;
}我们就可以做这样的事情
String a("apple");
String b;
b = std::move(a); //这里会直接调用 move operator =
Sting c = std::move(b); //这里则会调用 move constructor
//b将窃取a的资源:::danger 这里还要一个关于 cpp中的五三零规则需要考虑 :::