右值参数和移动

C++ Rvalue arrgument and move

本文关键字:移动 参数 值参      更新时间:2023-10-16

试图理解右值形式形参和按值调用形参的区别

当我调用fun(move(Demo{})时,我只看到默认构造函数被调用一次。当我调用gun(move(Demo{})时,我看到默认构造函数和rval构造函数被调用。请哪位帮帮我,让我理解一下……形式参数类型,使用&&在functions/成员函数中。

编译器clang++, g++, vc++

#include <iostream>
#include <utility>
#include <type_traits>
using namespace std;
class Demo {
    int i = 10;
public:
    Demo(){
        i = 40;
    }
    Demo(Demo && p) {
        i = p.i + 20;
        cout << "I am in Demo && " << endl;
    }
    Demo & operator = (Demo & p) {
        cout << "I am in operator && " << endl;
    }
    Demo & operator = (Demo && p) {
        i = p.i + 10;
        cout << "I am in operator && " << endl;
    }
    ~Demo(){
        cout << "I am in ~Demo " << i << endl;
    }
};
void fun(Demo & d) {
    cout << "fun( &) " << endl;
    cout << " -- End --  " << endl;
}
void fun(Demo && d) {
    cout << "fun( && ) " << endl;
    std::cout << std::boolalpha;
    cout << "Lvalur reference : " << is_lvalue_reference<decltype(d)>::value << endl;
    cout << "Rvalue Refernce  : " << is_rvalue_reference<decltype(d)>::value << endl;
    cout << " -- End --  " << endl;
}
void gun(Demo d) {
    cout << "gun( ) " << endl;
    std::cout << std::boolalpha;
    cout << "Lvalur reference : " << is_lvalue_reference<decltype(d)>::value << endl;
    cout << "Rvalue Refernce  : " << is_rvalue_reference<decltype(d)>::value << endl;
    cout << " -- End --  " << endl;
}
int main() {
    cout << "Main begin " << endl;
    fun(move(Demo{}));
    cout << "------------------- " << endl;
    gun(move(Demo{}));
    cout << "Main End " << endl;
}
<标题>//输出<>之前主要的开始乐趣(&&)值引用:false右值引用:true——结束——我在~Demo 40-------------------我在Demo &&枪()值引用:false右值引用:false——结束——我在~Demo 60我在~Demo 40主要的结束

简短的回答:右值引用的行为主要像通常的非const引用(我的意思是,非const左值引用),在你的代码中,它基本上与提供左值引用而不是右值引用相同(撇开区分它们的特征)。
不同之处在于,当你传递一个右值引用给一个函数/方法时,你是在告诉它"我不会再用它了,继续,用它做任何你想做的事情"。

更详细的回答:右值引用的出现是因为你可以用临时对象初始化或赋值对象,但没有它们,你必须:
-建立一个临时的
传递临时对象的const引用给方法/function
-清除静音对象
-有时重新分配内存来保存临时文件的内容
-复制临时文件的内容
-销毁临时的
简而言之,我们正在执行一个不必要的(并且可能代价高昂的)复制,而我们本可以简单地将临时对象的内容的所有权"移动"到静音对象(如果可能的话)。

右值引用的引入是为了在对象生命周期结束时,我们可以有一种类型来表示对象,这种类型可以自由修改,因为它们无论如何都不会再被使用。
它们被标记为&&(不要被误认为是"通用引用",在模板演绎上下文中也使用&&)。
通过值传递和通过右值引用传递的区别在于,传递值将调用复制构造函数并为您提供该对象的新实例,而通过右值引用传递(如前所述)的行为与传递通常的非const引用完全相同。
但是,我们不使用通常的非const引用,因为它们没有"相同的语义",如果构造函数将左值引用误认为右值引用,并且在我们打算使用复制构造函数时使用其move构造函数将对象击穿,则会出现问题。