【问题标题】:C++11 Convenience wrapper for std::reverse()用于 std::reverse() 的 C++11 便利包装器
【发布时间】:2012-04-19 10:52:10
【问题描述】:

这是使用 C++11 右值引用和移动语义为std::reverse() 实现便利包装器的正确方法吗?

template <class BIDirContainer> inline BIDirContainer&& reverse(BIDirContainer a) {
    std::reverse(begin(a), end(a));
    return std::move(a); 
}

代码在我的测试用例中有效,但我不确定它的性能:我应该在这里使用&amp;&amp; 还是不必要的?

【问题讨论】:

    标签: c++ algorithm stl c++11 wrapper


    【解决方案1】:

    如果您通过(右值)引用返回,那么您将获得一个悬空引用,因为a 是一个本地对象。按值返回,一切都应该“正常工作”。

    【讨论】:

    • @Nordlöw 不需要移动,除非BIDirContainer 没有移动构造函数的实现。请参阅下面的答案。
    • 在 C++11 中,如果您按值返回本地对象(例如本例中的 a),那么在第一个实例中编译器应将其直接构造为返回值,并且失败如果有的话,它应该使用移动构造函数。
    【解决方案2】:

    我想说正确的做法是从你的函数中按值返回:

    template <class BIDirContainer> inline BIDirContainer reverse(BIDirContainer a) {
        std::reverse(begin(a), end(a));
        return a; 
    }
    

    然后给BIDirContainer一个移动构造函数,如果它没有的话。那么这种表达方式:

    BIDirContainer x = ...;
    BIDirContainer backwards{reverse(x)};
    

    应该将reverse 函数中临时a 的内容移动到backwards

    【讨论】:

    • 所以对于 STL 容器(已经移动构造函数支持),正确的方法是既不使用&amp;&amp; 也不使用std::move,对吧?
    • @Nordlöw 在您的函数中都不使用它们,如果您正在实现移动构造函数,则仅在您的类中使用它们。如果您使用的是 C++11 容器,则无需执行任何操作。
    【解决方案3】:

    所以如果要修改参数...

    template <class BIDirContainer>
    inline BIDirContainer& reverse(BIDirContainer& a)
    {
        std::reverse(begin(a), end(a));
        return a;
    }
    

    如果您想制作反向副本,那么:

    template <class BIDirContainer>
    inline BIDirContainer reverse(BIDirContainer a)
    {
        std::reverse(begin(a), end(a));
        return a;
    }
    

    函数的返回值已经是一个右值(特别是“xvalue”)。如果您将它传递给具有移动语义的函数,它将被移动 - 但是由于上面的命名返回值优化 (NRVO) result 甚至可以就地构造(比移动语义更好)。

    【讨论】:

    • 当你通过ref时,为什么需要返回它?
    • 这如何解释右值引用?
    • @Jagannath:在第一个版本中,ref 是返回,因此您可以像 ostream 一样链接调用。我添加了更多细节。
    • 是的,您对第一个版本是正确的。但是对于第二个,仅按值获取参数就足够了。
    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    相关资源
    最近更新 更多