Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

r-value reference return type semantics?

Does a return type like this represent something meaningful in c++11?

template <typename R>
R&& grabStuff();

T instance = grabStuff<T>();

I would hope that grabStuff should throw a compile-time error if R does not have a move constructor, since this would seem to disallow the return type to use a copy constructor

like image 360
lurscher Avatar asked Apr 14 '12 15:04

lurscher


People also ask

What is an R value reference?

Rvalue references enable you to write one version of a function that accepts arbitrary arguments. Then that function can forward them to another function as if the other function had been called directly. Consider the following example that declares four types, W , X , Y , and Z .

What is R value Referene in C++ 11?

“l-value” refers to a memory location that identifies an object. “r-value” refers to the data value that is stored at some address in memory. References in C++ are nothing but the alternative to the already existing variable. They are declared using the '&' before the name of the variable.

How do rvalue references work?

An rvalue reference is formed by placing an && after some type. An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.

What is Move semantics in C++?

Move semantics is a set of semantic rules and tools of the C++ language. It was designed to move objects, whose lifetime expires, instead of copying them. The data is transferred from one object to another. In most cases, the data transfer does not move this data physically in memory.


2 Answers

As always, when returning references you must return a reference to something that's still alive after the function returns. How you do that is up to you. Example:

T global_thing;

T && get() { return std::move(global_thing); }

struct Foo { Foo(T &&); /* ... */ };

int main()
{
    global_thing.reset();
    Foo a(get());
    global_thing.reset();
    Foo b(get());
}

The more typical example for returning an rvalue reference is std::move itself, though, which returns a reference to the thing you pass into it (and thus it's the caller's responsibility to provide a valid input).

like image 96
Kerrek SB Avatar answered Oct 09 '22 11:10

Kerrek SB


If the return type of a function is an rvalue reference, then the result of the function call is an xvalue; if the return type is non-reference, then the result of the function call is a prvalue.

Both xvalue and prvalue are rvalues, there are some minor differences between them, more like differences between reference and non-reference. For example, an xvalue may have an incomplete type, while a prvalue shall usually have a complete type or the void type. When typeid is applied to an xvalue whose type is a polymorphic class type, the result refers to the dynamic type; and for prvalue, the result refers to the static type.

For your declaration statement T instance = grabStuff<T>();, if T is a class type, I think there is no difference between xvalue and prvalue in this context.

The initializer is an rvalue, so the compiler prefers a move constructor. But if no move constructor is declared, and a copy constructor with const reference parameter is declared, then this copy constructor will be chosen, and there is no error. I don't know why do you want this to be an error. If this is an error, any old code will be incorrect when copy-initialize some object from an rvalue.

like image 35
Cosyn Avatar answered Oct 09 '22 12:10

Cosyn