美文网首页每天写500字每周500字
[C++11阅读]移动语义和完美转发(上)

[C++11阅读]移动语义和完美转发(上)

作者: 凌霄阁2010 | 来源:发表于2020-05-22 08:26 被阅读0次

移动语义是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);
}

相关文章

网友评论

    本文标题:[C++11阅读]移动语义和完美转发(上)

    本文链接:https://www.haomeiwen.com/subject/ydliohtx.html