(rvalue reference) VS (const lvalue reference) as function parameters in C ++ 11

Can someone explain when rvalue references are preferable to const lvalue references when working as function parameters?

Background : I tried to pass a const pointer to a function. Since I have to consider cases in which a local pointer is passed and in which it is temporarily passed (say, from the return of a function call), I have two options: the parameter can be declared as:

void foo(T const* const&); //const lvalue ref to const ptr 

or

 void foo(T const* &&); //rvalue ref to const ptr 

But this rvalue link cannot be bound to a local variable (which is of type lvalue. But I remembered that Scott Meyers coined the term "universal link" to refer to the rvalue link, which confuses me more.) So my question is: since The first declaration can deal with both cases, when the second using rvalue reference will be preferable?

Note In the first approach, other forms

 void foo(const const T* &); void foo(const T* const&); 

does not work. I suppose the reason is that in the last two I have not been consistent in the place where the constant determinants are inserted (please correct me if I am wrong).

+6
source share
3 answers

It is very rarely recommended that you pass a pointer to const & : at best, it takes the same overhead, at worst, it causes extremely complex pointer re-search logic to surprise readers of your code.

Take pointer by value - T const* - and all will become more reasonable.

References to values ​​other than pointers make more sense.

Generic references is a method that uses rvalue and lvalue references in the context of type inference. This is mainly applicable only when you deduce the type T&& from the expression - in this context T can be X , X& or X const& (or other cv options).

If T is X& or X const& , the rvalue link to the lvalue link collapses to the lvalue link. This is an example of a standard committee that can and allows the use of universal reference variables auto&&x= , and the ideal forwarding code is easy to write.

+8
source

You do not want to distinguish between a temporary pointer and an lvalue pointer. It looks to me like something that can fail sooner rather than later.

Universal Refs only apply to template functions, e.g.

  template<class T> void foo(T && fwdref); 

Note that "universal ref" does not match rvalue ref.

+2
source

Note. I wrote this answer under the assumption that T in your question represents some actual data type - I chose int in my examples below.

Background: I tried to pass a const pointer to a function. [...] I have to consider cases in which a local pointer is passed and in which it is temporarily passed (say, from a function call)

You did not say what you mean by "const pointer". At first, I assume that you are referring to a pointer, which in itself is constant (i.e. the address it points to cannot be changed).

According to your description, there are two ways to get such a pointer:

 // Case 1 (what you call a local pointer -- this should be inside some // function body): int *const p = 0; // Case 2, a function that returns a pointer; this is your rvalue case // in contexts where f() is called and its return value used as a temporary: int *f() { return 0; } // Note: The temporary returned by this function isn't, strictly speaking, // constant. It could be modified as long as it is alive. But from // your description I take it that you have no intentions of doing so // and/or regard temporaries as generally constant. 

Now you can define a function that accepts these two cases as follows:

 void g(int *const &arg) { } 

You can apply this as g(p); to a constant, a local pointer, such as p , defined earlier, as well as to a temporary g(f()); . (You could, thirdly, apply it to a non-constant local pointer, because switching from a non-const lvalue to a const lvalue is never a problem.)

This function g has an argument to the arg function, which is defined as a constant, lvalue reference to an int pointer. It can bind to a constant (or really mutable) local pointer (like p ), as well as to a temporary one, because constant references to lvalue, unlike non-constant references to lvalue, can do this.

Note. I don’t understand why in this case you need the function argument to be a reference in general. You can simply declare void g(int *const arg) (without ampersand) and without help. Reasons include: a) you still cannot change it; b) In all realities of the real world, this link will take as much (or as little) as the pointer itself, so it makes no sense to avoid copying.

Anyway. If you want, you can also define a second version of g specifically for links rvalue:

 void g(int *&& arg) { } 

This can only be applied to a temporary pointer, not to a local pointer, because the function argument is defined as an rvalue reference, which can bind to temporary, but not lvalues.

However, if by “const pointer” you actually mean “pointer-to-const”, that is, a pointer that can be changed to different addresses, but does not have the right to change the value stored at these addresses, the declarations are slightly different. The const keyword should be placed in front of the asterisk, and for best clarity, it is best before the specifier of type int :

 // Declare local pointer-to-const: const int *p = 0; // Function that returns a pointer-to-const: const int *f() { return 0; } 

A function that can take these two will then be declared as:

 void g(const int *const &arg) { } 

The first const means that we are talking about constant pointers, and the second const ensures that we have the lvalue-reference constant, which can communicate with both rvalues ​​and lvalues. Note that this function cannot change what arg indicates, because arg declared as a constant lvalue reference. In the case where arg binds to the temporary, this is probably what we want anyway (as stated above). But in the case when the function is called as g(p); , we might want to change the local pointer p from g . If you want g have this power, you need to define two versions:

 void g(const int *&& arg) { /* Can bind to temporaries, but not modify them. */ } void g(const int *& arg) { /* Can bind to local variables and modify what they point at */ } 

Note 1: Your initial declaration of const int *const &const useless (and not even accepted by GCC). This would mean "a constant reference to a constant pointer to an int constant", but since the reference to a constant pointer is not a constant reference in itself, the final const is redundant (and is not provided by the standard).

Note 2: The universal reference does not coincide with the reference to the rvalue. Universal references are declared as T &&arg , where T is a template parameter. Depending on what T refers to each instance of the template, it may be a reference to an lvalue or a reference value of rvalue, therefore, its “universal” symbol. In any case, this has nothing to do with your use case, since you are dealing with T * pointers here (even if we assume that T is a template parameter).

+2
source

All Articles