Reference declaration - cppreference.com

Declares a named variable as a reference, that is, an alias to an already-existing object or function.

Syntax

A reference variable declaration is any simple declaration whose

declarator

has the form

&attr(optional)declarator(1) &&attr(optional)declarator(2) (since C++11)1)Lvalue reference declarator: the declaration S&D; declares D as an lvalue reference to the type determined by decl-specifier-seqS.

2)Rvalue reference declarator: the declaration S&&D; declares D as an rvalue reference to the type determined by decl-specifier-seqS.

declarator- any

declarator

except another reference declarator (there are no references to references) attr- (since C++11) list of

attributes

A reference is required to be initialized to refer to a valid object or function: see

reference initialization

.

The type “reference to (possibly cv-qualified) void” cannot be formed.

Reference types cannot be

cv-qualified

at the top level; there is no syntax for that in declaration, and if a qualification is added to a typedef-name or

decltype

specifier,(since C++11) or

type template parameter

, it is ignored.

References are not objects; they do not necessarily occupy storage, although the compiler may allocate storage if it is necessary to implement the desired semantics (e.g. a non-static data member of reference type usually increases the size of the class by the amount necessary to store a memory address).

Because references are not objects, there are no arrays of references, no pointers to references, and no references to references:

int&a[3];// errorint&*p;// errorint&&r;// errorReference collapsing

It is permitted to form references to references through type manipulations in templates or typedefs, in which case the reference collapsing rules apply: rvalue reference to rvalue reference collapses to rvalue reference, all other combinations form lvalue reference:

typedefint&lref;typedefint&&rref;intn;lref&r1=n;// type of r1 is int&lref&&r2=n;// type of r2 is int&rref&r3=n;// type of r3 is int&rref&&r4=1;// type of r4 is int&&(This, along with special rules for

template argument deduction

when T&& is used in a function template, forms the rules that make

std::forward

possible.)

(since C++11)Lvalue references

Lvalue references can be used to alias an existing object (optionally with different cv-qualification):

Run this code

#include<iostream>#include<string>intmain(){std::strings="Ex";std::string&r1=s;conststd::string&r2=s;r1+="ample";// modifies s// r2 += "!"; // error: cannot modify through reference to conststd::cout<<r2<<'\n';// prints s, which now holds "Example"}They can also be used to implement pass-by-reference semantics in function calls:

Run this code

#include<iostream>#include<string>voiddouble_string(std::string&s){s+=s;// 's' is the same object as main()'s 'str'}intmain(){std::stringstr="Test";double_string(str);std::cout<<str<<'\n';}When a function's return type is lvalue reference, the function call expression becomes an

lvalue

expression:

Run this code

#include<iostream>#include<string>char&char_number(std::string&s,std::size_tn){returns.at(n);// string::at() returns a reference to char}intmain(){std::stringstr="Test";char_number(str,1)='a';// the function call is lvalue, can be assigned tostd::cout<<str<<'\n';}Rvalue references

Rvalue references can be used to

extend the lifetimes

of temporary objects (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them):

Run this code

#include<iostream>#include<string>intmain(){std::strings1="Test";// std::string&& r1 = s1; // error: can't bind to lvalueconststd::string&r2=s1+s1;// okay: lvalue reference to const extends lifetime// r2 += "Test"; // error: can't modify through reference to conststd::string&&r3=s1+s1;// okay: rvalue reference extends lifetimer3+="Test";// okay: can modify through reference to non-conststd::cout<<r3<<'\n';}More importantly, when a function has both rvalue reference and lvalue reference

overloads

, the rvalue reference overload binds to rvalues (including both prvalues and xvalues), while the lvalue reference overload binds to lvalues:

Run this code

#include<iostream>#include<utility>voidf(int&x){std::cout<<"lvalue reference overload f("<<x<<")\n";}voidf(constint&x){std::cout<<"lvalue reference to const overload f("<<x<<")\n";}voidf(int&&x){std::cout<<"rvalue reference overload f("<<x<<")\n";}intmain(){inti=1;constintci=2;f(i);// calls f(int&)f(ci);// calls f(const int&)f(3);// calls f(int&&)// would call f(const int&) if f(int&&) overload wasn't providedf(std::move(i));// calls f(int&&)// rvalue reference variables are lvalues when used in expressionsint&&x=1;f(x);// calls f(int& x)f(std::move(x));// calls f(int&& x)}This allows

move constructors

,

move assignment

operators, and other move-aware functions (e.g.

std::vector::push_back()

) to be automatically selected when suitable.

Because rvalue references can bind to xvalues, they can refer to non-temporary objects:

inti2=42;int&&rri=std::move(i2);// binds directly to i2This makes it possible to move out of an object in scope that is no longer needed:

std::vector<int>v{1,2,3,4,5};std::vector<int>v2(std::move(v));// binds an rvalue reference to vassert(v.empty());Forwarding references

Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of

std::forward

. Forwarding references are either:

1) function parameter of a function template declared as rvalue reference to cv-unqualified

type template parameter

of that same function template:

template<classT>intf(T&&x)// x is a forwarding reference{returng(std::forward<T>(x));// and so can be forwarded}intmain(){inti;f(i);// argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvaluef(0);// argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue}template<classT>intg(constT&&x);// x is not a forwarding reference: const T is not cv-unqualifiedtemplate<classT>structA{template<classU>A(T&&x,U&&y,int*p);// x is not a forwarding reference: T is not a// type template parameter of the constructor,// but y is a forwarding reference};2)auto&& except when deduced from a brace-enclosed initializer list or, when representing a template parameter of a class template during

class template argument deduction

(since C++17):

auto&&vec=foo();// foo() may be lvalue or rvalue, vec is a forwarding referenceautoi=std::begin(vec);// works either way(*i)++;// works either wayg(std::forward<decltype(vec)>(vec));// forwards, preserving value categoryfor(auto&&x:f()){// x is a forwarding reference; this is a common way to use range for in generic code}auto&&z={1,2,3};// *not* a forwarding reference (special case for initializer lists)See also

template argument deduction

and

std::forward

.

(since C++11)Dangling references

Although references always refer to valid objects or functions upon initialization, it is possible to create a program where the

lifetime

of the referred-to object ends, but the reference remains accessible (dangling).

Given an expression expr of reference type and let target be the object or function denoted by the reference:

If a pointer to target would be

valid

in the context of the evalution of expr, the result designates target.

Otherwise, the behavior is undefined.

std::string&f(){std::strings="Example";returns;// exits the scope of s:// its destructor is called and its storage deallocated}std::string&r=f();// dangling referencestd::cout<<r;// undefined behavior: reads from a dangling referencestd::strings=f();// undefined behavior: copy-initializes from a dangling referenceNote that rvalue references and lvalue references to const extend the lifetimes of temporary objects (see

Reference initialization

for rules and exceptions).

If the referred-to object was destroyed (e.g. by explicit destructor call), but the storage was not deallocated, a reference to the out-of-lifetime object may be used in limited ways, and may become valid if the object is recreated in the same storage (see

Access outside of lifetime

for details).

Type-inaccessible references

Attempting to bind a reference to an object where the converted initializer is an lvalue(until C++11)a glvalue(since C++11) through which the object is not

type-accessible

results in undefined behavior:

charxalignas(int);int&ir=*reinterpret_cast<int*>(&x);// undefined behavior:// initializer refers to char objectCall-incompatible references

Attempting to bind a reference to a function where the converted initializer is an lvalue(until C++11)a glvalue(since C++11) whose type is not

call-compatible

with the type of the function's definition results in undefined behavior:

voidf(int);usingF=void(float);F&ir=*reinterpret_cast<F*>(&f);// undefined behavior:// initializer refers to void(int) functionNotes

Feature-test macroValueStdFeature

__cpp_rvalue_references

200610L

(C++11)

Rvalue references

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior

CWG 453

C++98 it was unclear which object or function a reference cannot be bound to made clear

CWG 1510

C++11 cv-qualified references could not be formed in the operand of decltypeallowed

CWG 2550

C++98 parameters could have type “reference to void” disallowed

CWG 2933

C++98 the behavior of accessing dangling references was unclear made clear External links