C++ 传递标准::字符串的最快方法

C++ Fastest way to pass a std::string?

本文关键字:方法 字符串 标准 C++      更新时间:2023-10-16

注意 ,我问这个问题是作为一个std::string特定的问题,而不是一个一般的如何传递一个对象

我会删除这个问题,但由于它的答案,我不允许这样做。我相信答案可能倾向于回答更普遍的问题,即"在C++中传递对象的最佳方法是什么?在堆栈溢出上有许多这些更通用的答案重复,即使这个精确的问题本身可能不是一个重复的问题。这种退化可能是因为这个问题是一个不恰当的问题,并且 std::string 类没有什么特别之处。这个问题没有很高的赞成票,这表明它并不有趣。在那种情况下,我的坏。也许一个mod会看到这个黑色的文字,怜悯我并杀死这个问题。

以下哪一个签名表示将非 const std::string 实例传递到不修改它的函数中的最快方法,同时考虑到调用站点调用的总体开销,包括在调用之前是否生成基础字符数组的深层副本?

extern void eat_string_by_value          (std::string s);
extern void eat_const_string_by_value    (const std::string s);
extern void eat_string_by_reference      (std::string& s);
extern void eat_const_string_by_reference(const std::string& s);

请注意,我问这个问题是作为一个特定于std::string的问题,而不是一个一般的如何传递对象的问题。特别是,我的问题受到以下因素的启发:

  • std::string handle-body 实现:是否有任何签名在调用站点暗示字符串主体及其后备字符数组的深层副本?
    • 请注意复制句柄(应该是轻量级(和复制正文(这将涉及内存分配(之间的区别。
  • C++98 与 C++>=11:这个版本分歧的两边有不同的答案吗?

我不认为我的问题与前一个问题重复,前一个问题本身被标记为传递一个的一般对象的副本<将参数传递为 或=" const=">因为这些特定于类型的详细点。

关于相关问题的有趣答案:

  • https://stackoverflow.com/a/10232761/506073
extern void eat_string_by_value          (std::string s);        // value
extern void eat_const_string_by_value    (const std::string s);
extern void eat_string_by_reference      (std::string& s);       // reference
extern void eat_const_string_by_reference(const std::string& s); // const-ref

首先,您错过了一个选项(自C++11以来(:

extern void eat_string_by_rvaluereference(std::string&& s);      // rvalue-ref

接下来,您的两个选项是相同的,因为顶级参数 cv 限定符不是函数签名的一部分:

extern void eat_string_by_value          (std::string s);
extern void eat_const_string_by_value    (const std::string s);

那么,让我们看看:

  1. 传递:
    缺点:调用方必须复制或移动到参数中。除非它在那里建造。
    优点:与所有人绑定。被调用方有自己的副本要修改。
  2. 通过引用:缺点:仅绑定到左值(非临时对象(。
    优点:被调用方可以修改传递的参数。
  3. 路过常量参考。缺点:如果需要,被调用方必须制作自己的副本。
    优点:对所有人都有约束力。
  4. 通过右值引用
    缺点:无法绑定到左值。如果绑定到常量对象,则复制。
    优点:可以清除传递的参数。

因此,by-value 几乎总是意味着一个副本(或至少是一个移动(,by-reference 意味着永远不会是一个副本(但对参数有不必要的限制(,其余的只有在需要转换时才复制。
by-const-ref 表示参数不能修改,by-rvalue-ref 表示可以重用其资源,这可能会在以后保存副本。

以下哪一个签名表示将非 const st::string 实例传递到不修改它的函数中的最快方法,同时考虑到调用站点调用的总体开销,包括在调用之前是否会生成基础字符数组的深层副本?

这要看情况。没有一种方法适用于所有情况,在所有方面

主要变量:

  • 你在通过什么?字符串的长度会影响哪种形式优于其他形式。
  • 编译器
  • 编译器选项和语言标准
  • 标准库
  • 呼叫站点是否需要副本?
  • 函数中的字符串会发生什么变化?
  • 按值传递可以开辟一些优化的可能性,但复制的成本通常更高。

没有一个答案/签名适合每种情况。

std::string handle-body 实现:是否有任何签名在调用站点暗示字符串主体及其后备字符数组的深层副本?

一些实现使用了 COW(写入时复制(,但这在 C++11 中不再有效。传递值将需要副本。如果库实现了 SSO,则对于短字符串,复制可能很快(=无堆分配(。

C++98 与 C++>=11:这个版本分歧的两边有不同的答案吗?

如上所述,COW不再有效。您可能会看到非常不同的性能特征。