std::string_view 在某些情况下更快。
首先,std::string const& 要求数据位于 std::string 中,而不是原始 C 数组、由 C API 返回的 char const*、由某些反序列化引擎生成的 std::vector<char> 等。格式转换避免了复制字节,并且(如果字符串比特定 std::string 实现的 SBO¹ 长)避免了内存分配。
void foo( std::string_view bob ) {
std::cout << bob << "\n";
}
int main(int argc, char const*const* argv) {
foo( "This is a string long enough to avoid the std::string SBO" );
if (argc > 1)
foo( argv[1] );
}
在string_view 的情况下不进行任何分配,但如果foo 使用std::string const& 而不是string_view,则会出现这种情况。
第二个真正重要的原因是它允许在没有副本的情况下使用子字符串。假设您正在解析一个 2 GB 的 json 字符串 (!)²。如果将其解析为std::string,则每个存储节点名称或值的此类解析节点复制将原始数据从 2 gb 字符串复制到本地节点。
相反,如果您将其解析为std::string_views,则节点引用原始数据。这可以在解析期间节省数百万次分配并将内存需求减半。
你可以获得的加速简直是荒谬的。
这是一个极端情况,但其他“获取子字符串并使用它”的情况也可以通过string_view 产生不错的加速。
决定的一个重要部分是使用std::string_view 会失去什么。不算多,但也有。
您失去了隐式空终止,仅此而已。因此,如果将相同的字符串传递给所有需要空终止符的 3 个函数,则转换为 std::string 一次可能是明智的。因此,如果已知您的代码需要一个空终止符,并且您不希望从 C 风格的源缓冲区等提供字符串,则可以使用 std::string const&。否则采取std::string_view。
如果std::string_view 有一个标志,表明它是否为空终止(或更奇特的东西),它甚至会删除使用std::string const& 的最后一个理由。
在某些情况下,采用不带 const& 的 std::string 优于 std::string_view。如果您需要在调用后无限期地拥有字符串的副本,则按值获取是有效的。您要么处于 SBO 的情况下(并且没有分配,只需几个字符副本即可复制它),要么您可以将堆分配的缓冲区 移动 到本地 std::string .有两个重载 std::string&& 和 std::string_view 可能会更快,但只是很小,它会导致适度的代码膨胀(这可能会让你失去所有的速度提升)。
¹小缓冲区优化
² 实际用例。