错误转发右值参考

时间:2013-04-12 10:16:22

标签: c++ c++11 rvalue

我正在尝试新增的右值参考(在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;)只是一个简单的左值引用。但是参考什么?

2 个答案:

答案 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));
}