用于 std::reverse() 的 C++11 便利包装器

Posted

技术标签:

【中文标题】用于 std::reverse() 的 C++11 便利包装器【英文标题】:C++11 Convenience wrapper for std::reverse() 【发布时间】: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; 还是不必要的?

【问题讨论】:

【参考方案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 backwardsreverse(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 一样链接调用。我添加了更多细节。 是的,您对第一个版本是正确的。但是对于第二个,仅按值获取参数就足够了。

以上是关于用于 std::reverse() 的 C++11 便利包装器的主要内容,如果未能解决你的问题,请参考以下文章

std::async 可以与模板函数一起使用吗

c++ 容器反转

pybind11 用于 C++14/C++17

c++11 统一初始化不适用于“g++ -std=c++0x”

g++ 不包含它说它包含用于 C++11 的文件?

用于更新 MFC 应用程序窗口的 C++11 线程。需要 SendMessage()、PostMessage() 吗?