16、C++11移动构造函数

本节主要讲解移动语义的含义以及实现它的方式。

C++ 98/03 标准中,想用其他对象初始化一个同类的新对象,只能借助拷贝构造函数。(原理是为新对象复制一份和其他对象一模一样的数据)

#include<iostream>
using namespace std;

class Demo{
public:
    Demo():num(new int(10))
    {
        cout<<"construct"<<endl;
    }
    //拷贝构造函数
    Demo(const Demo &d):num(new int(*d.num))
    {
        cout<<"copy construct"<<endl;
    }
    ~Demo()
    {
        cout<<"class destruct"<<endl;
    }
private:
    int *num;  
};

Demo get_demo()
{
    return Demo();
}

int main()
{
    Demo a = get_demo();
    return 0;
}
/*
construct!                <-- 执行 Demo()
copy construct!       <-- 执行 return Demo()
class destruct!         <-- 销毁 Demo() 产生的匿名对象
copy construct!       <-- 执行 a = get_demo()
class destruct!         <-- 销毁 get_demo() 返回的临时对象
class destruct!         <-- 销毁 a
*/
  • 利用拷贝构造函数实现对 a 对象的初始化,底层实际上进行了 2 次拷贝(而且是深拷贝)操作。
  • 对少量堆空间的临时对象来说可以接受,但如果临时对象中的指针成员申请了大量的堆空间,那么 2 次深拷贝操作势必会影响 a 对象初始化的执行效率。

问题:当类中包含指针类型的成员变量。使用它来初始化同类对象时,怎样才能避免深拷贝导致的效率问题呢?

C++11 标准引入了解决方案,该标准中引入了右值引用的语法,借助它可以实现移动语义。

C++移动构造函数(移动语义的具体实现)

移动语义:以移动而非深拷贝的方式初始化含有指针成员的类对象。即将临时对象拥有的内存资源“据为己有”。

移动构造函数操作步骤:

  • ① 将临时对象的指针成员浅拷贝。
  • ② 将临时对象的指针成员置为nullptr。
#include<iostream>
using namespace std;

class Demo{
public:
    Demo():num(new int(10))
    {
        cout<<"construct"<<endl;
    }
    //拷贝构造函数
    Demo(const Demo &d):num(new int(*d.num))
    {
        cout<<"copy construct"<<endl;
    }
    //移动构造函数
    Demo(Demo &&d):num(d.num)    //临时对象指针成员浅拷贝
    {
        d.num = nullptr;         //临时对象的指针成员置为nullptr
        cout<<"move construct"<<endl;
    }
    ~Demo()
    {
        cout<<"class destruct"<<endl;
    }
private:
    int *num;  
};

Demo get_demo()
{
    return Demo(); // Demo()调用construct, 返回值为临时对象调用move construct, Demo()调用class destruct
}

int main()
{
    Demo a = get_demo(); // 给a初始化调用move construct,销毁get_demo()临时对象调用class destruct,a超过作用域调用class destruct
    return 0;
}
/*
construct!
move construct!
class destruct!
move construct!
class destruct!
class destruct!
*/
  • 当为 demo 类添加移动构造函数之后,使用临时对象初始化 a 对象过程中产生的 2 次拷贝操作,都转由移动构造函数完成。

总结

  • 当用户利用右值初始化类对象时,会调用移动构造函数;
  • 使用左值(非右值)初始化类对象时,会调用拷贝构造函数。

如果想左值对象初始化同类对象时也通过 移动构造函数 完成呢?

  • 可以使用C++11的std::move()函数,它可以将左值强制转换成对应的右值,由此可以使用移动构造函数。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值