今天任性,想写一个自己感兴趣的问题,move 语义。
先上代码
#include <iostream>
class A {
public:
A() {
std::cout << "constructor A" << std::endl;
}
~A() {
std::cout << "destructor A" << std::endl;
}
};
A func () {
A a;
return std::move(a);
}
int main() {
auto a = func();
std::cout << "flag 1" << std::endl;
return 0;
}
问题是打印什么?
如果没有 move 语义,我想你一定知道打印什么,现在的问题是有了 move 之后,现在你还能知道吗?
上结果,然后说下原因
constructor A
destructor A
flag 1
destructor A
move 抵消了一次 constructor, 但是却出现了两次 destructor,这个和传统 C++ 是相悖的。那么现在有问题了,由于调用了两次 destructor 如何解决资源重复释放的问题?比如我在构造函数里面 new 了一个对象,需要在析构函数里面释放,这个问题怎么解决?
C++ 使用了一个 move constructor, 这个东西有点类似 copy constructor,代码如下:
#include <iostream>
class A {
public:
A() {
std::cout << "constructor A" << std::endl;
}
~A() {
std::cout << "destructor A" << std::endl;
}
A( A & oth) {
std::cout << "copy constructor A" << std::endl;
}
A(A && oth) {
std::cout << "move constructor A" << std::endl;
}
};
A func () {
A a;
return std::move(a);
}
int main() {
A a = func();
std::cout << "flag 1" << std::endl;
return 0;
}
输出结果如下:
constructor A
move constructor A
destructor A
flag 1
destructor A
好了,资源释放的问题,我们就放到 move constructor 里面,为了对比,我写个 copy constructor 的过程,去除了所有可能的异常case,只是做个示范,代码如下:
#include <iostream>
class A {
public:
A() {
std::cout << "constructor A" << std::endl;
num = new int(100);
}
~A() {
if (num == nullptr) {
std::cout << ">>>>num is nullptr" << std::endl;
} else {
std::cout << ">>>>num value is " << *num << std::endl;
delete num;
}
std::cout << "destructor A" << std::endl;
}
A( A & oth) {
std::cout << "copy constructor A" << std::endl;
num = new int;
num = oth.num;
}
A(A && oth) {
std::cout << "move constructor A" << std::endl;
num = std::move(oth.num);
oth.num = nullptr;
}
public:
int * num;
};
A func () {
A a;
return std::move(a);
}
int main() {
A a = func();
std::cout << "flag 1" << std::endl;
return 0;
}
看到区别了吗,move constructor 是不需要 new 新对象的,只要将对应的字段也move一下,原有的字段设置成一个无效的值就行了,这样就保证了资源的安全,代码运行结果如下:
constructor A
move constructor A
>>>>num is nullptr
destructor A
flag 1
>>>>num value is 100
destructor A
这里面有很多的问题,我没有说完,比如如果不写move constructor, 程序会crash 吗?