Incorrect rvalue link forwarding

I experimented with newly added rvalue links (in vs2012 express).

I do not understand anything. Given the code below (most of it is 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 do not understand where m_i is bound.

Basically I get the lvalue link to the rvalue (& &) link, which, according to the rules for dropping ref, becomes (&) just equal to lvalue ref. But the link to what?

+6
source share
2 answers

I do not understand where m_i is bound.

m_i bound to the argument of constructor A What is the argument of constructor A ?

In this case, since the factory does not redirect its argument to A (i.e. does not use std::forward<>() ), then what is passed to A is an lvalue. This is due to the fact that a1 is named, and the named objects are lvalues.

The type a1 not relevant for determining whether a1 value of l or a value of r. So even if a1 is of type rvalue-reference for int ( int&& ), as in your program, parameter a1 itself is a named object, and therefore it is an lvalue.

This means that since m_i is of type lvalue-reference for int , m_i can bind (and is really bound) to the factory (lvalue) parameter a1 , which will be destroyed when factory() returns. In other words, you are left with a sagging link.

Attempting to dereference it (as later in your program) causes Undefined Behavior .

However, if your factory() function redirected its arguments to constructor A :

 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 cause a compiler error because the std::forward<>() mechanism would ensure that lvalues ​​remain lvalues ​​and rvalues ​​remain rvalues. Attempting to bind an lvalue-reference to an rvalue is illegal, and therefore calling constructor A would fail.

+10
source

But the link to what?

This behavior is undefined. As you may have guessed, this is a temporary reference that was destroyed on the stack of the factory function. To catch such problems at compile time you need to use std::forward

 template<class T, class A1, class A2> T* factory(A1&& a1, A2&& a2) { return new T(std::forward<A1>(a1), std::forward<A2>(a2)); } 
+3
source

All Articles