【问题标题】:Why std::string append is not overloaded on rval ref?为什么 std::string append 在 rval ref 上没有重载?
【发布时间】:2020-11-10 16:08:26
【问题描述】:

我很熟悉,std::string 中的append 返回std::string&,因此它不符合被移动的条件,因此结果不会被移动。

#include <string>


int main()
{
    std::string s = std::string("A").append("B");
    return s.size();
}

https://godbolt.org/z/M63aWW

#include <string>


int main()
{
    std::string s = std::move(std::string("A").append("B"));
    return s.size();
}

https://godbolt.org/z/jTnsac

您可以看到,后一个示例将产生更少的分配,因此在这种情况下,最好移动一些看起来像临时的东西。我的问题是为什么他们(委员会)不根据上下文在&amp;&amp; 上添加简单的重载以使append 的结果为std::string&amp;std::string&amp;&amp;?我的意思是类似于std::optional 的事情正在处理value。有没有例子可以证明这种优化是假的?

【问题讨论】:

  • 你能发布一个实际有用的例子吗?自动 res = std::string("A").append("B");剂量真的很有意义。
  • @Cortex 是的,这没有意义,但是当您尝试连接几个字符串时,可能会非常大,您希望尽可能少地重新分配。而append 将重用缓冲区,因此总体分配会更少。
  • 解决方法:std::string s = std::move(std::string("A").append("B")); 但对所有这一切都很重要。这不是一个引人注目的用例。

标签: c++ stdstring rvalue-reference stdoptional


【解决方案1】:

正如 P1165R1 中所述,basic_stringoperator+ 的分配器传播规则很复杂,并且是不同库实现不一致的根源。

使有状态的分配器传播对于 operator+(basic_string) 更加一致

[...] basic_stringoperator+ 的分配器传播是随意的、不一致的,并且是实现分歧的根源。让他们保持一致。 [...]

P1165R1 已被 C++20 接受。

append() 成员函数与operator+(P1165R1 之前)没有相同的语义,没有重载,也没有遭受相同的“偶然性...” .前者没有理由加入后者的领域; basic_string 已经是一个容器的怪物(你的反例 optional 不是这种情况,它不是标准意义上的容器,即使它具有类似于 stl 容器的语义)。

【讨论】:

    【解决方案2】:

    您不能简单地添加&amp;&amp; 重载。您还必须创建原始函数&amp;。这可能是一个重大变化。

    所有这些都是为了很少的收获。由于append() 修改了源字符串并返回*this 更多用于链接而不是将结果分配给其他任何东西,因此您编写的代码是单调的。如果需要,请使用+,这是为表达式结果构建字符串的惯用形式,并且已经具有必要的重载以提高效率:

    auto s = "A"s + "B";
    

    【讨论】:

    • 我有两件事。这里是"A"s + "B",但是随着字符串变大并且有两个以上的字符串,这将在每个+ 上重新分配缓冲区,使其有点不理想。当&amp;&amp; 过载时,添加&amp; 将如何破坏代码?我不明白。
    • @koscelansky 检查overloads 6-12 是否有operator+ - 他们在内部进行移动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 2011-05-05
    • 2021-05-10
    • 1970-01-01
    • 2012-08-17
    相关资源
    最近更新 更多