移动语义是C++11中提升代码执行性能最重要的新特性,也是最复杂的特性之一。
移动构造函数
提出移动构造函数的动机是复制构造函数昂贵的开销,用移动构造可以少一次内存拷贝,如下图,在占内存特别大的类中收益明显。

此时先给出移动构造函数的示例,&&的含义,至于何时会被触发,后面会讲到。
#include <iostream>
using namespace std;
class HasPtrMem
{
public:
HasPtrMem(): d(new int(3))
{
cout << "Construct: " << ++n_cstr << endl;
}
HasPtrMem(const HasPtrMem & h): d(new int(*h.d))
{
cout << "Copy construct: " << ++n_cptr << endl;
}
HasPtrMem(HasPtrMem && h): d(h.d)
{
h.d = nullptr;
cout << "Move construct: " << ++n_mvtr << endl;
}
~HasPtrMem()
{
delete d;
cout << "Destruct: " << ++n_dstr << endl;
}
int * d;
static int n_cstr, n_cptr, n_mvtr, n_dstr;
};
int HasPtrMem::n_cstr = 0;
int HasPtrMem::n_cptr = 0;
int HasPtrMem::n_mvtr = 0;
int HasPtrMem::n_dstr = 0;
HasPtrMem GetTemp()
{
HasPtrMem h;
cout << "Resource from " << __func__ << ": " << hex << h.d << endl;
return h;
}
int main()
{
HasPtrMem a = GetTemp();
cout << "Resource from " << __func__ << ": " << hex << a.d << endl;
}
// g++ -std=c++11 test.cpp -o test -fno-elide-constructors
/* ./test输出为
Construct: 1
Resource from GetTemp: 0x121ac20
Move construct: 1
Destruct: 1
Move construct: 2
Destruct: 2
Resource from main: 0x121ac20
Destruct: 3
*/
在上面的程序中,构造函数被调用了一次,在GetTemp函数内h定义的地方,移动构造函数被调用了两次,分别是GetTemp函数内把临时变量h给返回值,main内把GetTemp返回值给a。
第一次调用移动构造函数,因为h是内部变量,是将亡值(eXpiring Value,xvalue),退出要被销毁,被作为右值看待,移动语义变相延长了h的生命周期,销毁前移交给了一个匿名临时变量,返回值。
第二次调用移动构造函数,因为GetTemp的返回值在等号右边,是个纯右值(Pure Rvalue,prvalue),销毁前移交给了左值a。
prvalue是C++98就有的概念,xvalue是C++11新增的。所有的值,都属于lvalue、xvlaue、prvalue三者之一。
移动赋值函数
移动构造函数与移动赋值函数是成对出现的,移动构造函数由括号触发,移动赋值函数由等号触发。
实际上与拷贝构造函数、拷贝赋值函数一起,四者同时出现。
移动赋值函数重载了=操作符,将一个右值引用赋值给左值引用。
以下例子同时给了四个函数,移动构造、拷贝构造、移动赋值、拷贝赋值。
TrackFeatureExtractResultFace(TrackFeatureExtractResultFace&& other) :
pRecognizeResult(std::move(other.pRecognizeResult)),
pDetectResult(std::move(other.pDetectResult))
{ }
TrackFeatureExtractResultFace(const TrackFeatureExtractResultFace& other)
{
(*this) = other;
}
TrackFeatureExtractResultFace& operator=(TrackFeatureExtractResultFace&& other)
{
if (this == &other)
return (*this);
pRecognizeResult = std::move(other.pRecognizeResult);
pDetectResult = std::move(other.pDetectResult);
return (*this);
}
TrackFeatureExtractResultFace& operator=(const TrackFeatureExtractResultFace& other)
{
if (this == &other)
return (*this);
pRecognizeResult.reset();
if (other.pRecognizeResult)
{
pRecognizeResult = std::unique_ptr<RecognizeResult>(
new RecognizeResult(*(other.pRecognizeResult)));
}
pDetectResult.reset();
if (other.pDetectResult)
{
pRecognizeResult = std::unique_ptr<RecognizeResult>(
new RecognizeResult(*(other.pRecognizeResult)));
}
return (*this);
}
网友评论