【问题标题】:Wrong forwarding of rvalue reference右值引用的错误转发
【发布时间】:2013-04-12 10:16:22
【问题描述】:

我正在试验新添加的右值引用(在 vs2012 express 中)。

我有些不明白。给定下面的代码(其中大部分来自解释 std::forward 的 c++ 标准)。

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 绑定到哪里。

我基本上会有一个对右值引用 (& &&) 的左值引用,通过 ref 折叠规则变成 (&) 只是一个普通的左值 ref。但是参考什么?

【问题讨论】:

    标签: c++ c++11 rvalue


    【解决方案1】:

    我不明白 m_i 绑定到哪里。

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

    在这种情况下,由于factory 确实 将其参数转发给A(即它不使用std::forward&lt;&gt;()),那么传递给A 的是一个左值。这是因为a1命名的,而命名的对象是左值

    a1类型 与确定 a1 是左值还是右值无关。因此,即使 a1 具有类型 rvalue-reference 到 int (int&amp;&amp;),就像您的程序中的情况一样,参数 a1 本身就是一个命名对象,因此它是一个左值。

    这意味着,由于m_i 具有对int 的左值引用类型,因此m_i 可以 绑定(并且确实是绑定)到factory 的(左值)参数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&lt;&gt;() 的机制会确保左值保持左值,而右值保持右值。尝试将左值引用绑定到右值是非法的,因此对A 的构造函数的调用将失败。

    【讨论】:

    • 正如 Scott Meyers 所指出的,任何使用通用引用(T&amp;&amp; 和类型推断的 T)而没有 std::forwardstd::move 至少是可疑的.现在我可以清楚地看到原因了。
    【解决方案2】:

    但是参考什么?

    这是一种未定义的行为。正如您猜对的,它是对在函数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));
    }
    

    【讨论】:

    • A1&amp;&amp; a1 不必是 rvalue_ref 它也可以接受 lvalue_ref,因为它们的类型是由模板推断的。因此,每当模板推断出一个类型并且您不想在函数调用之间保留引用的类型时,您必须使用std::forward
    • ups....我不小心删除了我的评论。谢谢。旧评论:我是否总是需要将 std::forward 与左值引用一起使用? )
    猜你喜欢
    • 2018-02-10
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 2016-01-01
    相关资源
    最近更新 更多