14

Possible Duplicate:
What does T&& mean in C++11?

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.

Community
  • 1
  • 1
Daniel
  • 6,595
  • 9
  • 38
  • 70
  • 1
    @Fred: I'd vote to leave both open, the answers of the duplicate your mention use Standardese speak heavily, while templatetypedef's answer below gives a neat explanation of the use (but not really the definition) in layman's terms. – Matthieu M. Aug 23 '11 at 06:34
  • 3
    @Matthieu: Can't the questions (and therefore answers) be merged, since they're the same question? We shouldn't keep two questions that are the same open. – Nicol Bolas Aug 23 '11 at 09:47

2 Answers2

37

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 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++11 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.

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++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.

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;
}

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. 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.

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;
}

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++11, 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);
}

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.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 1
    Could you provide a simple code example that demonstrates its use? – Daniel Aug 22 '11 at 21:54
  • 1
    @Daniel- Yup, just did! Let me know if there's anything else I can clarify! – templatetypedef Aug 22 '11 at 21:56
  • 1
    Just be sure that after being "destructively modified" the class must still be valid. The important part of that is: it should still be destructible, and assignable. – Mooing Duck Aug 22 '11 at 22:44
  • @Mooing Duck- Thanks for pointing that out! I just updated the answer to explain this and why it's necessary. – templatetypedef Aug 22 '11 at 22:50
  • Excellent explanation of the use of rvalue references! – Matthieu M. Aug 23 '11 at 06:32
  • @templatetypedef Awesome! Very good explanation. That's pretty nifty. I actually only figured out a few days ago that you can't normally reference an rvalue. Spent a long time figuring that out, and an even longer time trying to come up with a work-around. Looking back now, this is exactly what I needed... Too bad I didn't ask this then. – Daniel Aug 23 '11 at 13:21
  • This helps indeed! Thank you! – Zaar Hai Sep 29 '19 at 13:31
  • Great answer. But I was somewhat intrigued by the use of "input(filename)" in the first code snippet. Where can I find more information about "input"? I know this is tangential to the topic under discussion. But I couldn't find it explained or mentioned elsewhere. – venk Feb 07 '21 at 16:38
  • `input` is a variable of type `ifstream`. Searching for that type might give you some more information. Hope this helps! – templatetypedef Feb 07 '21 at 20:10
2

It's not a reference to a reference. It's a new syntax introduced in C++0x for so-called Rvalue references.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
sepp2k
  • 363,768
  • 54
  • 674
  • 675