在这种情况下,使用 string_view 会导致不必要的字符串复制吗?

Posted

技术标签:

【中文标题】在这种情况下,使用 string_view 会导致不必要的字符串复制吗?【英文标题】:Does using string_view lead to an unnecessary string copy in this scenario? 【发布时间】:2020-05-28 20:12:02 【问题描述】:

我想做的是让我的班级在构造过程中接受一个字符串。我读到string_viewconst string& 的替代品,所以我很自然地写了一个这样的构造函数。这让我可以接受 c++ 和 c 字符串。

Url::Url(boost::string_view raw_url)
    : url_(static_cast<std::string>(raw_url)) 

这里可能存在的问题是,当传递一个右值时,会有一个不必要的副本而不是移动。是制作另一个采用string&amp;&amp; 的构造函数的解决方案吗?这里的最佳做法是什么?

【问题讨论】:

应该移入一些数据的构造函数通常只接受值,而不是右值引用。这更简单。 创建一个构造函数,按值获取参数并将其移动到url_ 重点是移入​​会员url_(std::move(raw_url)),那么你只会得到一份。对于左值,您将获得额外的移动,但您只需要编写一个处理所有情况的构造函数。与我猜想的更多样板代码相比,这取决于额外移动对性能的重要性。 【参考方案1】:

注意:我会考虑std::string_view 来写答案,但boost::string_view 应该是相似的。


我读到 string_view 是 const string& 的替代品

了解最初添加std::string_view 的原因很有用。

const string&amp; 有什么问题?

如果你传递一个std::string 对象并且你没有得到任何std::string_view 的东西,那肯定是有效的。但是现在假设您正在传递一个包含大字符串的char*。在这种情况下,将创建一个临时的std::string 对象(并且将复制该char* 引用的整个字符串),以便函数接收std::string。那是std::string_view 发光的时候。如果您将char*std::string(或任何可以转换为std::string_view 的东西)传递给接受std::string_view 的函数(按值,无需通过引用接受std::string_view),那么新的@创建的 987654338@ 对象非常便宜,因为它只是“一个视图”,它不会复制底层字符串。


但你的情况不同。由于您无论如何都在复制字符串,那么您的函数应该只接受一个字符串按值并将字符串移动到函数内。诸如

之类的东西
Url::Url(std::string raw_url)
    : url_(std::move(raw_url)) 

甚至还有clang-tidy warning 告诉你这一点。

优点是,如果你的函数的用户传递了一个左值,你会创建一个副本(无论如何你都需要它)和一个移动,但如果他们传递一个右值,那么就没有副本,只有一个移动。

【讨论】:

这不是等效代码 - 此类函数不接受 string_view 作为参数。 你是对的。它不接受string_view。然而,似乎 OP 尝试使用 string_view 而不是字符串的唯一原因是出于效率考虑,在他的特殊情况下,按值传递的常规字符串似乎是更好的选择。 如果确实需要,也可以添加一个采用 string_view 的构造函数 @M.M 它不起作用,因为const char* 转换变得模棱两可。这就是为什么我不喜欢 clang-tidy 在这种情况下建议的原因 - 唯一“有效”的方法是提供 3 个重载:const char *std::string_viewstd::string&amp;&amp;

以上是关于在这种情况下,使用 string_view 会导致不必要的字符串复制吗?的主要内容,如果未能解决你的问题,请参考以下文章

在这种情况下使用管道会导致 write() 失败吗?

在这种情况下如何使用双缓冲?

std::string_view 编译时散列

如何在这种情况下避免同步?

带有释放器的 string_view

使用 string_view 在 unordered_map 中查找