我正在尝试新增的右值参考(在vs2012 express中)。
我不明白。鉴于下面的代码(大部分来自c ++标准,其中解释了std :: forward)。
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;
}
我不明白m_i绑定到哪里。
我基本上会对右值参考(&amp;&amp;&amp;&amp;)进行左值引用,ref refpsing规则变为(&amp;)只是一个简单的左值引用。但是参考什么?
答案 0 :(得分:10)
我不明白m_i绑定到哪里。
m_i
绑定到A
的构造函数的参数。这里A
的构造函数的论点是什么?
在这种情况下,由于factory
不将其参数转发给A
(即它不使用std::forward<>()
),因此传递给的是A
a1
是左值。这是因为a1
命名为,命名对象是左值。
a1
的类型与确定a1
是左值还是右值无关。因此,即使int
具有类型 rvalue-reference to int&&
(a1
),与程序中的情况一样,参数m_i
也是本身就是一个命名对象,因此它是一个左值。
这意味着,由于int
具有m_i
的类型左值引用,factory
可以绑定(并且确实已绑定)到{{1 } {lvalue}参数a1
,在factory()
返回时将被销毁。换句话说,你留下了一个悬空参考。
尝试取消引用它(正如您稍后在程序中所做的那样)召唤未定义的行为。
但是,如果您的factory()
函数已将转发其参数转发给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));
}
这会导致编译器错误,因为std::forward<>()
的机制会确保左值保持左值,并且rvalues保持rvalues。尝试将左值引用绑定到右值是非法的,因此对A
的构造函数的调用将失败。
答案 1 :(得分:3)
但是参考什么?
这是一种未定义的行为。正如您所猜测的那样,它是对函数factory
的堆栈中被破坏的临时引用的引用。要在编译时捕获此类问题,您需要使用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));
}