Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modern double reference

Tags:

c++

I've been learning a bit of modern C++, improving my code style and stuff, then I got to that part where I actually don't understand certain thing. It is basically anything with double reference:

for (auto&& i = 0; i <= iNumber; ++i){
    std::cout << vecStrings[i] << std::endl; 
}

vs

for (auto i = 0; i <= iNumber; ++i){
    std::cout << vecStrings[i] << std::endl; 
}

what is the difference here? i've tried a lot of stuff, but it doesn't really act any different.

like image 961
dadas dasdas Avatar asked Feb 26 '26 03:02

dadas dasdas


1 Answers

This notation is new in C++11, and is part of "move mechanics." The basic idea is that we have discovered that there are a lot of cases where C++ has to copy an object as part of passing it as an argument to a function. In many of those cases, that copy operation involves a memory allocation. For example, if you need to copy a string, you have to create a new memory block to store the copy of the text in that string.

We found they occur often enough that it was worth improving the language to get around them. We created the idea of an "rvalue reference," which is a type that ends in &&. It is not a "double reference" or "a reference to a reference." It's simply a symbol which indicates that this is a rvalue reference.

If you get an rvalue reference passed to you, it means that the caller of your function was willing to use "move" mechanics on that rvalue instead of the usual copy mechanics. With move mechanics, the caller basically states "I don't intend to use this variable anymore after this point, so if you want to cannibalize it and 'move' the data out of it, I don't mind." The spec also provides an obvious use case for you: temporary variables are now created as "rvalue references", so that you can steal the contents out of them (they're just going to get deallocated at the end of the line, anyways)

To use the most common example, copying a string, the std::string(std::string&&) constructor accepts a "rvalue reference." This newly constructed string now knows that the caller doesn't mind if we steal the data right out of the old string. Thus, this constructor simply copies the data pointer out of the old string, and then sets the old string's pointer to null (or something else which has the effect of "moving" ownership of the data from one string to another). This is far more efficient than allocating new space for a copy of the string, when we know we're just going to deallocate the old one moments later.

In your case, its a bit absurd. There's no point in cannibalizing content out of an int, and I don't think you could do it if you tried. It's just superflouous syntax. However, there could be cases where it does matter. For example, you may be writing a function which moves data from one vector to another. If you were passed the vector by "rvalue reference," you know the caller doesn't mind if you canabalize its data. If you use auto&& to refer to elements in that vector, you can now pass those elements to another function and tell it "I don't care if you cannibalize the content of this element," because you know your caller doesn't mind either.

In either case, the syntax permits it. It's a useful syntax in a few corner cases (std::move comes to mind). For the most part, it's overkill.

like image 127
Cort Ammon Avatar answered Mar 03 '26 18:03

Cort Ammon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!