Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对函数的直观理解引用的引用_C++_Pass By Reference_Rvalue Reference_C++11 - Fatal编程技术网

C++ 对函数的直观理解引用的引用

C++ 对函数的直观理解引用的引用,c++,pass-by-reference,rvalue-reference,c++11,C++,Pass By Reference,Rvalue Reference,C++11,可能重复: 出于某种原因,这是我的直觉,我无法在互联网上找到任何解释。C++函数引用引用的含义是什么?例如: void myFunction(int&& val); //what does this mean?! 我理解通过引用传递的想法,所以 void addTwo(int& a) { a += 2; } int main() { int x = 5; addTwo(x); return 0; } 这不是引用的引用,而是

可能重复:

出于某种原因,这是我的直觉,我无法在互联网上找到任何解释。C++函数引用引用的含义是什么?例如:

void myFunction(int&& val);     //what does this mean?!
我理解通过引用传递的想法,所以

void addTwo(int& a)
{
    a += 2;
}

int main()
{
    int x = 5;
    addTwo(x);

    return 0;
}

这不是引用的引用,而是一种称为的新语言功能,它(非正式地)表示对内存中某个对象的引用,该对象在程序的其他地方没有引用,可以进行破坏性修改。例如,右值引用可以捕获函数的返回值,表达式中引入的临时值也可以捕获

右值引用可用于多种用途。从大多数C++程序员的角度来看,它们可以被用来实现,从而可以通过“移动”旧对象的内容从旧对象和新对象初始化新的对象。您可以使用它从C++11中的函数返回巨大的对象,而无需支付复制该对象的巨大成本,因为用于捕获返回值的对象可以使用move构造函数初始化,只需从return语句创建的临时对象中窃取内部内容

移动语义与复制语义正交,因此对象可以在不可复制的情况下移动。例如,
std::ofstream
s是不可复制的,但它们是可移动的,因此您可以使用移动行为从函数返回
std::ofstream
s。这在C++03中目前无法完成。例如,此代码在C++03中是非法的,但在C++11中却非常好(并受到鼓励!):

std::ifstream GetUserFile() {
    while (true) {
        std::cout << "Enter filename: ";
        std::string filename;
        std::getline(std::cin, filename);

        ifstream input(filename); // Note: No .c_str() either!
        if (input) return input;

        std::cout << "Sorry, I couldn't open that file." << std::endl;
    }
}

std::ifstream file = GetUserFile(); // Okay, move stream out of the function.
需要注意的是,当我们在构造函数末尾清除
rhs
时,我们最终将
rhs
置于这样一种状态,即

  • 当其析构函数调用时不会导致崩溃(注意,我们将其元素指针设置为
    nullptr
    ,因为释放
    nullptr
    是安全的),并且
  • 仍然允许为对象指定新值。后一点很棘手,但重要的是要确保您仍然可以在某个点为清除的对象指定一个新值。这是因为可以获得对对象的右值引用,该对象以后仍可以在程序中引用
  • 为了说明(2),右值引用的一个有趣的用例是能够在对象之间显式地移动值。例如,考虑代码< >交换< /代码>:< /P>
    template <typename T> void swap(T& lhs, T& rhs) {
        T temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
    

    现在,根本没有复制品。我们将
    lhs
    的内容移动到
    temp
    ,然后将
    rhs
    的内容移动到
    lhs
    ,然后将
    temp
    的内容移动到
    rhs
    。在这样做时,我们将
    lhs
    rhs
    暂时置于“清空”状态,然后再将新值放入其中。重要的是,在编写代码以将内容移出对象时,我们要使对象保持某种格式良好的状态,以便此代码正常工作。

    它不是对引用的引用。这是C++0x中引入的一种新语法,用于所谓的。

    您能提供一个简单的代码示例来演示它的用法吗?@Daniel-是的,刚刚做了!如果还有什么我可以澄清的,请告诉我!只需确保在被“破坏性修改”之后,类必须仍然有效。重要的一点是:它仍然应该是可破坏的,并且是可分配的。@mooingduck-谢谢你指出这一点!我刚刚更新了答案来解释这一点以及为什么它是必要的。非常好地解释了右值引用的使用@弗雷德:我赞成保留这两个选项的开放性,重复你提到的问题的答案使用了标准化的语言,而templatetypedef下面的答案用外行的术语给出了一个简洁的解释(但不是真正的定义)。@Matthieu:问题(和答案)不能合并,因为它们是同一个问题吗?我们不应该让两个相同的问题悬而未决。
    template <typename T> void swap(T& lhs, T& rhs) {
        T temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
    
    template <typename T> void swap(T& lhs, T& rhs) {
        T temp = std::move(lhs);
        lhs = std::move(rhs);
        rhs = std::move(temp);
    }