I was experimenting with the newly added rvalue refernces ( in vs2012 express ).
I don't understand something tho. Given the code below ( most of it taken from the c++ standard where std::forward is explained ).
struct A
{
A(int& i, const float& j):
m_i(i),
m_j(j){}
int& m_i;
const float& m_j;
};
template<class T, class A1, class A2>
T* factory(A1&& a1, A2&& a2)
{
return new T(a1, a2);
}
void test()
{
A* a1 = factory<A>(1, 1.2f);
//How does this work ?
a1->m_i = 2;
}
I don't understand where is m_i binded to.
I will basically have a lvalue reference to an rvalue reference (& &&), that by the ref collapsing rules becomes (&) just a plain lvalue ref. But a reference to what?
I don't understand where is m_i binded to.
m_i
is bound to the argument of A
's constructor. What is the argument of A
's constructor here?
In this case, since factory
does not forward its argument to A
(i.e. it does not use std::forward<>()
), then what is being passed to A
is an lvalue. This is because a1
is named, and named objects are lvalues.
The type of a1
is not relevant to determine whether a1
is an lvalue or an rvalue. So even though a1
has type rvalue-reference to int
(int&&
), as is the case in your program, the parameter a1
is itself a named object, and therefore it is an lvalue.
This means, since m_i
has type lvalue-reference to int
, that m_i
can be bound (and indeed is bound) to factory
's (lvalue) parameter a1
, which will be destroyed when factory()
returns. In other words, you're left with a dangling reference.
Attempting to dereference it (as you do later on in your program) summons Undefined Behavior.
However, if your factory()
function had forwarded its arguments to A
's constructor:
template<class T, class A1, class A2>
T* factory(A1&& a1, A2&& a2)
{
return new T(std::forward<A1>(a1), std::forward<A2>(a2));
}
This would have caused a compiler error, because the machinery of std::forward<>()
would make sure that lvalues stay lvalues, and rvalues stay rvalues. Attempting to bind an lvalue-reference to an rvalue is illegal, and therefore the call to A
's constructor would have failed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With