账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    c++ 拷贝构造和移动构造同时存在 导致 move 的行为差异
    • 2019-10-01 00:00
    • 10
    38
    0

    首先我粗浅的认为同时存在没有问题,因为

    • 一个是创建一个变量副本
    • 一个转移一个生存周期将到的变量所申请的资源

    环境

    g++.exe (Rev2, Built by MSYS2 project) 9.2.0

    g++.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0

    实验

    sf 抽风,源码见 http://code.bulix.org/k07gcm-891664


    A( const A& c )A( A&& c ) 同时存在的输出

    this: 0x66f880 @ A()0
            申请内存:0x732760
    this: 0x737d50 @ A( A&& c )0
            移动内存: 0x732760
    this: 0x66f880 @ ~A()0
            被移动内存: 0
    
    this: 0x66f880 @ A()1
            申请内存:0x737d70
    this: 0x737dc0 @ A( A&& c )1
            移动内存: 0x737d70
    this: 0x737db0 @ A( const A& c )99  // ???
            this: 0x737d50 0
            申请内存:0x737de0
    
    this: 0x737d50 @ ~A()0
            释放内存: 0x732760
    this: 0x66f880 @ ~A()1
            被移动内存: 0
    over
    0x737db0 : 99 // ???
    0x737dc0 : 1
    this: 0x737db0 @ ~A()99
            释放内存: 0x737de0
    this: 0x737dc0 @ ~A()1
            释放内存: 0x737d70

    可见 调用了拷贝构造函数,这是不是内部没有使用 std::move 导致调用拷贝构造函数?(瞎猜)

    只有 A( A&& c ) 时的输出

    this: 0x66f880 @ A()0
            申请内存:0x1f2760
    this: 0x1f7d50 @ A( A&& c )0
            移动内存: 0x1f2760
    this: 0x66f880 @ ~A()0
            被移动内存: 0
    
    this: 0x66f880 @ A()1
            申请内存:0x1f7d70
    this: 0x1f7dc0 @ A( A&& c )1
            移动内存: 0x1f7d70
    this: 0x1f7db0 @ A( A&& c )0
            移动内存: 0x1f2760
    this: 0x1f7d50 @ ~A()0
            被移动内存: 0
    this: 0x66f880 @ ~A()1
            被移动内存: 0
    over
    0x1f7db0 : 0
    0x1f7dc0 : 1
    this: 0x1f7db0 @ ~A()0
            释放内存: 0x1f2760
    this: 0x1f7dc0 @ ~A()1
            释放内存: 0x1f7d70

    问题 2

    class A a( 2 );
    vect.push_back( std::move( a ) );

    输出

    this: 0x66f880 @ A()0
            申请内存:0x1f2760
    this: 0x1f7d50 @ A( A&& c )0
            移动内存: 0x1f2760
    this: 0x66f880 @ ~A()0
            被移动内存: 0

    这个应该是 push_back 的源码

    push_back(value_type&& __x)
    { emplace_back(std::move(__x)); }

    为什么只调一次移动构造函数,被优化了?

    +------------------------------+
    |   在 这 里 创 建 变 量        |
    +------------------------------+
    
    vect.push_back( std::move( a ) );
    +------------------------------+
    |    调 用 移 动 构 造 函 数     |
    +------------------------------+
    
    emplace_back(std::move(__x));   //  <<<
    +------------------------------+
    | push_back 内 部 也 有 move    |
    | 为 什 么 不 会 再 次 调 用 移 动 构 造    |
    | 函 数                        |
    +------------------------------+
    0
    打赏
    收藏
    点击回答
    您的回答被采纳后将获得:提问者悬赏的 10 元积分
        全部回答
    • 0
    • 长弓难鸣 普通会员 1楼

      在C++中,拷贝构造和移动构造通常会同时存在,这是因为它们都用于创建一个对象的副本。然而,当创建一个对象的副本时,如果这个副本的指针指向同一个内存区域,那么移动构造将覆盖拷贝构造。反之,如果指针指向不同的内存区域,那么拷贝构造将不会覆盖移动构造。

      例如,假设我们有以下两个对象:

      cpp class MyClass { public: MyClass() {} MyClass(MyClass&& other) { // 拷贝构造 *this = other; } MyClass(const MyClass& other) { // 移动构造 *this = other; } };

      在这种情况下,如果我们创建一个副本mySecondObject,并将其赋值给mySecondObject = *this;,那么mySecondObject将引用同一个内存区域,这意味着移动构造将覆盖拷贝构造。

      相反,如果我们创建一个副本myThirdObject,并将其赋值给myThirdObject = *this;,那么myThirdObject将引用不同的内存区域,这意味着拷贝构造将不会覆盖移动构造。

      因此,如果你想确保移动构造不会覆盖拷贝构造,你应该使用move运算符,如下所示:

      cpp class MyClass { public: MyClass(MyClass&& other) { // 移动构造 *this = move(other); } MyClass(const MyClass& other) { // 拷贝构造 *this = other; } };

      在这种情况下,即使mySecondObject = *this;myThirdObject也会是另一个对象,因为它引用的是不同的内存区域。

    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部