【问题标题】:specializing std::swap for rvalues将 std::swap 专门用于右值
【发布时间】:2014-02-27 20:02:29
【问题描述】:

在标准(20.2.2 [utility.swap])中,std::swap 是为左值引用定义的。我知道这是您想要交换两件东西的常见情况。但是,有时交换右值是正确且可取的(当临时对象包含引用时,例如这里:swap temporary tuples of references)。

为什么右值没有重载?对右值进行无意义交换的风险是否大于潜在收益?

是否有合法的方式来支持交换包含引用的右值 std::tuple 对象?对于用户定义的类型,我会专门使用 swap 来按值接受其参数,但对于像 std::tuple 这样的库类型,这样做似乎并不合理。

【问题讨论】:

  • 交换它们的行为会立即要求将它们转换为左值,这意味着您可以使用std::swap
  • 这不是和将右值分配给左值对象基本一样吗?因为临时的无论如何都不能在之后使用,所以它还不如直接(右值)赋值而不是交换。
  • 我需要一些理由来证明“有时交换右值是正确和可取的(当临时对象包含引用时......)”,我认为你错了。就像@Excelcius 所说,交换右值似乎在语义上没有意义。
  • 您不能 swap 包含引用的元组:引用无法交换。
  • @Yakk 但为了使其有意义,这些参数中的至少 1 个 必须 是左值......否则它什么也不做。并且尝试交换引用无论如何都会中断,因为您无法将引用重新分配到新位置(根据定义它们不可交换§ 17.6.3.2)。

标签: c++ c++11


【解决方案1】:

不如创建一个 lvalue_cast 实用函数,将右值转换为左值:

#include <tuple>
#include <iostream>

template <class T>
T&
lvalue_cast(T&& t)
{
    return t;
}

int
main()
{
    int i = 1;
    int j = 2;
    swap(lvalue_cast(std::tie(i)), lvalue_cast(std::tie(j)));
    std::cout << i << '\n';
    std::cout << j << '\n';
}

【讨论】:

  • 因为交换引用——因此包含引用的元组——仍然是 UB。
  • @Casey: 有人忘了告诉委员会([tuple.assign]/p3)。不默认元组复制分配的全部原因是处理 tuple 情况。
  • 17.6.3.2/2要求swap(t, u)swap(u, t)的效果是“t引用的对象具有u原本持有的值和引用的对象by u 具有最初由 t 持有的值。” Does this program not demonstrate that requirement doesn't hold for tuples of references?
  • lvalue_cast 重命名为copy 怎么样?这将更符合move ;)
  • @HowardHinnant 您是否暗示编译器会警告所有可能发生的未定义行为?
【解决方案2】:

如果迭代器产生 r 值(例如临时值),某些 STL 算法似乎需要交换 r 值。

swap 是否应该与 r 值一起工作是一个有效的讨论。 我经常看到这个问题,因为对于“特殊”迭代器,*it 会产生一个 r 值,有时您希望在“交换”时做正确的事情。

我发现不处理这个问题的解决方法是首先将std::iter_swap 专门用于这些特殊的迭代器。 我认为这解决了所有 STL 算法的问题。

namespace std{
void iter_swap(special_iterator it1, special_iterator it2){
   ... special swap of pointed values
}
}

我认为这是所有置换 STL 算法都错过和缺乏的基本定制点。

(当然,如果我们要破解 STL,我们也可以这样做 namespace std{template&lt;class T, ...enable_if T&amp;&amp; is r-value ref just in case...&gt; void swap(T&amp;&amp; t1, T&amp;&amp; t2){swap(t1, t2);}。但风险更大。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-05
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2017-10-09
    • 2015-09-30
    相关资源
    最近更新 更多