6

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?

4

2 回答 2

10

我不明白 m_i 绑定到哪里。

m_i绑定到A的构造函数的参数。这里的构造函数的参数是什么A

在这种情况下,由于factory其参数转发给A(即不使用std::forward<>()),因此传递给A的是左值。这是因为a1命名的,而命名对象是左值。

类型a1确定a1是左值还是右值无关。因此,即使具有对( ) 的a1类型右值引用 ,就像您的程序中的情况一样,参数本身也是一个命名对象,因此它是一个左值。intint&&a1

这意味着,由于m_i具有对 的左值引用类型int,因此m_i 可以将其绑定(并且确实已绑定)到factory的 (lvalue) 参数,该参数将在返回a1时被销毁。factory()换句话说,你留下了一个悬空的参考。

尝试取消引用它(就像您稍后在程序中所做的那样)会调用Undefined Behavior

但是,如果您的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<>()会确保左值保持左值,而右值保持右值。尝试将左值引用绑定到右值是非法的,因此对A的构造函数的调用将失败。

于 2013-04-12T10:23:20.580 回答
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));
}
于 2013-04-12T10:22:36.767 回答