考虑下面的代码
struct Test {Test() { std::cout << "Test::Test\n"; }Test(const Test& rhl) : val_{rhl.val_} {std::cout << "Test(const Test&) called" << std::endl;}Test(Test&& rhl) : val_{rhl.val_}{std::cout << "Test(Test&&) called" << std::endl;}~Test() { std::cout << "Test::~Test destructor\n"; }int val_ { 0 };
};int main() {const Test t2;Test t3{std::move(t2)};}
我们知道,通过移动操作从一个对象中“窃取”数据的时候,被窃取的那个对象会被修改。这也是为什么移动构造函数要声明成Test(Test&&)的原因。当我们对一个const对象进行移动时,直觉上可能会认为,无法编译通过。毕竟移动操作会修改源对象,但是原对象又是一个const对象,很矛盾。但是实际上上面的代码可以编译通过。
输出如下:
Test::Test
Test(const Test&) called
Test::~Test destructor
Test::~Test destructor
可见,如果试图对一个const对象进行移动操作,最终会使用拷贝来作为一个变通方法。
如果拷贝构造函数声明为delete,那么才会编译报错。
但是最好不要对const对象应用移动操作,如果这个对象尺寸很大的话,拷贝操作的代价很高。