移动构造

最后更新于 2024-06-07 549 次阅读


CSDN:a只如初见 / c语言中文网

http://t.csdn.cn/oSedW / http://m.biancheng.net/view/7847.html

移动构造是C++11标准中提供的一种新的构造方法。

先举个生活例子,你有一本书,你不想看,但我很想看,那么我有哪些方法可以让我能看这本书?有两种做法,一种是你直接把书交给我,另一种是我去买一些稿纸来,然后照着你这本书一字一句抄到稿纸上。

显然,第二种方法很浪费时间,但这正是有些深拷贝构造函数的做法,而移动构造函数便能像第一种做法一样省时,第一种做法在 C++ 中叫做完美转发

  • 在C++11之前,如果要将源对象的状态转移到目标对象只能通过复制。
    而现在在某些情况下,我们没有必要复制对象,只需要移动它们。
  • C++11引入移动语义:源对象资源的控制权全部交给目标对象。

所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解,移动语义指的就是将其他对象(通常是临时对象)拥有的内存资源“移为已用”。

移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的初值是一个右值引用。这意味着,移动构造函数的参数是一个右值或者将亡值的引用。也就是说,只有当用一个右值,或者将亡值初始化另一个对象的时候,才会调用移动构造函数。

class Str
{
public:
    char *str;
    Str(char value[])
    {
        cout << "普通构造函数..." << endl;
        str = NULL;
        int len = strlen(value);
        str = (char *)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, value);
    }
    Str(const Str &s)
    {
        cout << "拷贝构造函数..." << endl;
        str = NULL;
        int len = strlen(s.str);
        str = (char *)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, s.str);
    }
    Str(Str &&s)
    {
        cout << "移动构造函数..." << endl;
        str = NULL;
        str = s.str;
        s.str = NULL;
    }
    ~Str()
    {
        cout << "析构函数" << endl;
        if (str != NULL)
        {
            free(str);
            str = NULL;
        }
    }
};
int main()
{
    char value[] = "I love zx";
    Str x("hhh");
    Str s(value);
    vector<Str> vs;
    vs.push_back(move(s));
    // vs.push_back(s);
    cout << vs[0].str << endl;
    if (s.str != NULL)
        cout << s.str << endl;
    return 0;
}

在实际开发中,通常在类中自定义移动构造函数的同时,会再为其自定义一个适当的拷贝构造函数,由此当用户利用右值初始化类对象时,会调用移动构造函数;使用左值(非右值)初始化类对象时,会调用拷贝构造函数。

移动构造常见于STL

    _CONSTEXPR20 void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
        emplace_back(_Val);
    }

    _CONSTEXPR20 void push_back(_Ty&& _Val) {
        // insert by moving into element at end, provide strong guarantee
        emplace_back(_STD move(_Val));
    }

std::move()作用

默认情况下,左值初始化同类对象只能通过拷贝构造函数完成,如果想调用移动构造函数,则必须使用右值进行初始化。C++11 标准中为了满足用户使用左值初始化同类对象时也通过移动构造函数完成的需求,新引入了 std::move() 函数,它可以将左值强制转换成对应的右值,由此便可以使用移动构造函数。

优点

移动构造函数是c++11的新特性,移动构造函数传入的参数是一个右值 用&&标出。

首先讲讲拷贝构造函数:拷贝构造函数是先将传入的参数对象进行一次深拷贝,再传给新对象。这就会有一次拷贝对象的开销,拷贝的内存越大越耗费时间,并且进行了深拷贝,就需要给对象分配地址空间。而移动构造函数就是为了解决这个拷贝开销而产生的。

移动构造函数首先将传递参数的内存地址空间接管,然后将内部所有指针设置为nullptr,并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间。即提高程序的执行效率,节省内存消耗。

总结

  • 移动构造是C++11标准中提供的一种新的构造方法
  • 移动构造接管源对象,既不会产生额外的拷贝开销,也不会给新对象分配内存空间。提高程序的执行效率,节省内存消耗。
  • 移动构造函数的第一个参数必须是自身类型的右值引用