直观地理解参考引用的函数 [英] Intuitive understanding of functions taking references of references

查看:109
本文介绍了直观地理解参考引用的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:

什么是T& C ++ 11中的平均值?

由于某种原因,直觉,我在互联网上找不到任何解释。 C ++函数获取引用的引用是什么意思?例如:

For some reason, this is eluding my intuition, and I cannot find any explanation on the internet. What does it mean for a C++ function to take a reference of a reference? For example:

void myFunction(int&& val);     //what does this mean?!

我理解通过引用传递的想法,因此

I understand the idea of passing-by-reference, so

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

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

    return 0;
}

有效,对我来说是直观的。

works and is intuitive to me.

推荐答案

这不是引用的引用,而是一种新的语言特性,称为右值引用,表示(非正式)对内存中对象的引用,该对象在程序中未被引用,可以被破坏性修改。例如,函数的返回值可以通过右值引用捕获,也可以引入到表达式中的临时值。

This is not a reference of a reference, but rather a new language feature called an rvalue reference that represents (informally) a reference to an object in memory that isn't referenced elsewhere in the program and can be destructively modified. For example, the return value of a function can be captured by an rvalue reference, as can temporary values introduced into expressions.

Rvalue引用可用于各种目的。从大多数C ++程序员的角度来看,它们可以用于实现移动语义 ,由此可以通过将旧对象的内容从旧对象移动到新对象中来初始化新对象。你可以使用它从C ++ 0x中的函数返回巨大的对象,而不需要花费巨大的成本来复制对象,因为用于捕获返回值的对象可以使用move构造函数来初始化,只需从临时对象中窃取内部由返回语句创建。

Rvalue references can be used for a variety of purposes. From the perspective of most C++ programmers, they can be used to implement move semantics, whereby a new object can be initialized by "moving" the contents of an old object out of the old object and into a new object. You can use this to return huge objects from functions in C++0x without paying a huge cost to copy the object, since the object used to capture the return value can be initialized using the move constructor by just stealing the internals from the temporary object created by the return statement.

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

Move semantics are orthogonal to copy semantics, so objects can be movable without being copyable. For example, std::ofstreams are not copyable, but they will be movable, so you could return std::ofstreams from functions using the move behavior. This currently cannot be done in C++03. For example, this code is illegal in C++03 but perfectly fine (and encouraged!) in C++0x:

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.



直观地说,一个接受右值引用的函数是(可能)试图避免通过将旧对象的内容移动到新对象中来创建昂贵的副本。例如,您可以通过让该构造函数接受一个右值引用,为一个向量类对象定义一个 move constructor 。如果我们将向量表示为指向数组的指针,数组的容量和使用的空间的三倍,我们可以如下实现它的move构造函数:

Intuitively, a function that takes an rvalue reference is a function that (probably) is trying to avoid an expensive copy by moving the contents of an old object into a new object. For example, you could define a move constructor for a vector-like object by having that constructor take in an rvalue reference. If we represent the vector as a triple of a pointer to an array, the capacity of the array, and the used space, we might implement its move constructor as follows:

vector::vector(vector&& rhs) {
    /* Steal resources from rhs. */
    elems    = rhs.elems;
    size     = rhs.size;
    capacity = rhs.capacity;

    /* Destructively modify rhs to avoid having two objects sharing 
     * an underlying array.
     */
    rhs.elems    = nullptr; // Note use of nullptr instead of NULL
    rhs.size     = 0;
    rhs.capacity = 0;
}



重要的是要注意,当我们清除 rhs 到构造函数的末尾,我们最终将 rhs 改成这样的状态:

It's important to notice that when we clear out rhs at the end of the constructor that we end up putting rhs into such a state that


  1. 当析构函数调用时,不会导致崩溃(注意,我们将其元素指针设置为 nullptr ,因为释放 nullptr 是安全的)和

  2. 仍然让对象分配一个新值。后一点是棘手的,但重要的是要确保你仍然可以给清除出的对象一个新的值。这是因为可以获得对稍后仍然可以在程序中引用的对象的右值引用。

  1. Will not cause a crash when its destructor invokes (notice that we set its element pointer to nullptr, since freeing nullptr is safe), and
  2. Still lets the object be assigned a new value. This latter point is tricky, but it's important to ensure that you can still give the cleared-out object a new value at some point. This is because it is possible to obtain an rvalue reference to an object that can still be referenced later in the program.

light on(2),右值引用的一个有趣的用例是在对象之间显式地移动值的能力。例如,考虑 swap 这个惯用的实现:

To shed some light on (2), one interesting use case for rvalue references is the ability to explicitly move values around between objects. For example, consider this idiomatic implementation of swap:

template <typename T> void swap(T& lhs, T& rhs) {
    T temp = lhs;
    lhs = rhs;
    rhs = temp;
}

这段代码是合法的,但它有点不寻常。特别是,它最终创建三个副本 - 首先,当设置 temp 等于 lhs 的副本时, code>为 rhs 的副本,并且一旦设置 rhs 成为 temp 的副本。但我们真的不想在这里做任何副本;相反,我们只是想洗掉这些值。因此,在C ++ 0x中,您可以使用 std :: move 函数显式获取对象的右值引用:

This code is legal, but it's a bit unusual. In particular, it ends up making three copies - first when setting temp equal to a copy of lhs, once setting lhs to be a copy of rhs, and once setting rhs to be a copy of temp. But we don't really want to be making any copies at all here; instead, we just want to shuffle the values around. Consequently, in C++0x, you'll be able to explicitly get rvalue references to objects by using the std::move function:

template <typename T> void swap(T& lhs, T& rhs) {
    T temp = std::move(lhs);
    lhs = std::move(rhs);
    rhs = std::move(temp);
}

现在,根本没有复制。我们将 lhs 的内容移动到 temp ,然后移动 rhs into lhs ,然后将 temp 的内容移动到 rhs 。在这样做时,我们在将新值放入其中之前,暂时将 lhs rhs 重要的是,当编写代码以将对象中的内容移出对象时,我们将该对象留在一个格式良好的状态,以便此代码可以正常工作。

Now, no copies are made at all. We move the contents of lhs into temp, then move the contents of rhs into lhs, then moves the contents of temp into rhs. In doing so, we left both lhs and rhs in an "emptied" state temporarily before putting new values into them. It's important that when writing the code to move the contents out of an object that we leave the object in a somewhat well-formed state so that this code works correctly.

Hope这有助于!

这篇关于直观地理解参考引用的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆