首页 > 其他分享 >构造函数,移动语义move与右值引用

构造函数,移动语义move与右值引用

时间:2023-08-05 23:11:05浏览次数:62  
标签:调用 右值 对象 move 拷贝 移动 构造函数

构造函数

C++的构造函数包含一般构造函数,拷贝构造函数与移动构造函数。

拷贝构造函数

  1. 其中包含浅拷贝和深拷贝(此处以深拷贝为例),主要是通过将已存在的对象的所有成员拷贝给新对象,来实现对新对象的初始化。这样就会存在两个一样的对象,相当于内存中存在两份。
  2. 拷贝构造函数的参数是一个左值引用,即为该类对象的常引用

移动构造函数

  1. 移动构造函数通过将已存在对象的资源转移给新对象(资源控制权的转移),来实现对新对象的初始化,而不必进行拷贝。此时旧对象资源就会转移给新对象,而旧对象就成为右值,将亡值。此时内存中该对象也只存在一份。
  2. 移动构造函数的形参是一个右值引用,其形式为 T&& 形式,其中T为类型。
  3. 对于使用临时的对象来构造新的对象,且后续不会再使用该临时对象,此时更适合使用移动构造函数。因为移动构造函数让新对象直接接管和使用临时对象的资源以及内存空间,来实现初始化,避免了重新分配内存空间进拷贝操作,提高了新对象的初始化效率,同时节省不必要的内存。
  4. 可以通过 std::move()函数来实现对移动构造函数的调用。因为该函数可以将左值变成右值引用。
class A 
{
public:
    // 构造函数
    A(int val1) 
    {
        printf("Constructor......\n");
        num1 = val1;
    }

    // 拷贝构造函数
    A(const A& obj): num1(obj.num1)
    {
        printf("Copy Constructor +++++\n");
    }


    // 移动构造函数
    A(A&& obj)
    {
        printf("Move Constructor ====\n");
        num1 = obj.num1;
    }
    
private:
    int num1;

};

int main()
{
    int val = 10; // val为左值

    A a1(val); // 调用构造函数
    A a2 = a1; // 调用拷贝构造函数,a2与a1一样,a1相当于a2的一个副本
    A a4(a1);  // 调用拷贝构造函数,传入的参数相当于对象的左值引用
    A a4(std::move(a2));// 调用移动构造函数, a2的资源将被转移给a4,避免拷贝副本
}

运行结果如下图所示,根据传入的参数类型,来调用对应的构造函数。


std::move() 函数

std::move()函数主要是用来实现语义转换,可以将左值转换成右值,调用移动构造函数来实现对新对象的初始化。
STL中的容器大部分都已经有移动构造函数的实现,vector::push_back为例,其有拷贝构造函数和移动构造函数两种实现,如下图:

int main()
{
    string str1 = "hello just a test";
    vector<string> vec;

    // 调用拷贝构造函数
    vec.push_back(str1);
    std::cout <<"Copy push, str1 = "<< std::quoted(str1) << endl;

    // 调用移动构造函数后,旧对象str1将被释放
    vec.push_back(std::move(str1));
    std::cout << "Move push, str1 = " << std::quoted(str1) << endl;
}

结果如下图,在调用拷贝构造函数之后,相当于Copy了一个副本,此时 str中任然是之前的值。而调用移动构造函数之后,旧对象str的资源及所有权都转移到新的对象中,在此处即为vector容器的元素,然后旧对象str作为一个将亡值就被释放了,此时打印的旧对象值就是空的。


【参考资料】

  1. What is std::move(), and when should it be used and does it actually move anything?

标签:调用,右值,对象,move,拷贝,移动,构造函数
From: https://www.cnblogs.com/Jeffxu/p/17608690.html

相关文章

  • 【转载】C/C++ 通过初始化列表和构造函数内赋值初始化成员变量的区别
    【结论】一、在有些情况下,必须使用初始化列表。特别是const和引用数据成员被初始化时。二、从效率方面来说,对于内置类型或复合类型,差异不会太大,但对于非内置数据类型,差异还是很明显的【具体参考】C/C++通过初始化列表和构造函数内赋值初始化成员变量的区别_Zju_Jemery的博客-......
  • C++入门到放弃(07)——构造函数和析构函数
    ​1.构造函数和析构函数是什么1.1构造函数通常一个类,其内部包含有变量和函数,当我们想要使用类的时候,总是会不得不面临这样一个问题,需要对类进行初始化,否则内部这些变量就会是随机值,导致程序出现异常。为此,我们需要在使用类之前对它进行初始化,C++就提供了这样一类特殊的函数——......
  • 完整记录 ROS2 MoveIt! 项目编写过程
    目的是编写一个简单的项目,根据一个特定的机器人模型生成moveit配置文件,并根据配置文件模拟控制机器人,以学习为目的。这里使用的环境为moveit2humble。创建一个名叫ur5_project的文件夹作为工作区,后续工作都在其中进行。创建软件包ur_description没有找到现成能用的UR5......
  • odoo post account move
    D:\odoo\odoo16\addons\stock_account\models\stock_valuation_layer.py_validate_accounting_entriesifam_vals:print(am_vals)print('-------------------------------------')foreachinam_vals:......
  • Qt moveToThread使用及注意事项
    在Qt中,每个QObject对象都有一个线程关联,这个线程被称为对象的“线程上下文”。默认情况下,一个QObject对象的线程上下文与创建它的线程相同。也就是说,如果我们在主线程中创建了一个QObject对象,那么这个对象的线程上下文就是主线程。在某些情况下,我们可能需要将一个QObject对象(或......
  • remote: Support for password authentication was removed on August 13, 2021
    一、问题描述remote:SupportforpasswordauthenticationwasremovedonAugust13,2021.Pleaseuseapersonalaccesstokeninstead.具体如下:  大概意思:你原先的密码凭证从2021年8月13日开始就不能用了,必须使用个人访问令牌(personalaccesstoken),就是把你的密码替......
  • [Javascript] removeEventListener
    Mistake1:Notusingthesamefunctionreference//Wrongbutton.addEventListener('click',()=>{console.log('click')})button.removeEventListener('click',()=>{console.log('click')})//Won'tremovet......
  • 无涯教程-jQuery - remove( expr )方法函数
    remove(expr)方法从DOM中删除所有匹配的元素。这不会将它们从jQuery对象中删除,而是允许您进一步使用匹配的元素。与empty()方法进行比较。remove(expr)-语法selector.remove(expr)这是此方法使用的所有参数的描述-expr   - 这是一个可选的jQuery表达式,用于......
  • memcpy/memmove模拟实现
    void*my_memmove(void*dest,constvoid*src,size_tnum){ assert(dest&&src); void*ret=dest; if((char*)dest<(char*)src)//从前向后移 { while(num--) { *(char*)dest=*(char*)src; dest=(char*)dest+1; src=(char*)src+1; } } else......
  • Remove Linked List Elements
    SourceProblemRemoveallelementsfromalinkedlistofintegersthathavevalueval.ExampleGiven1->2->3->3->4->5->3,val=3,youshouldreturnthelistas1->2->4->5题解删除链表中指定值,找到其前一个节点即可,将next指向下一个节点即可。Java/**......