C ++传递std :: string的最快方法?

时间:2014-12-09 20:51:29

标签: c++ c++11 deep-copy stdstring c++98

注意 我问这是一个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 implementation:任何签名是否都意味着在主叫站点的字符串主体及其支持字符数组的深层副本?
    • 请注意复制句柄(应该是轻量级)和复制正文(这将涉及内存分配)之间的区别。
  • C ++ 98与C ++> = 11:这个版本划分的任何一方是否有不同的答案?

我不认为我的问题是前一个问题的副本,它本身被标记为传递一个<的一般对象的副本。 Pass arguments as std::string or const std::string&?>因为这些特定类型的详细点。

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

2 个答案:

答案 0 :(得分:6)

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. 传递
    缺点:调用者必须复制或移入参数。除非它在那里建造。
    优势:与所有人结合。 Callee有自己的副本进行修改。
  2. 通过参考传递: 缺点:仅绑定左值(非临时对象) 优点:Callee可以修改传递的参数。
  3. 通过 const-ref 传递。 缺点:如果需要,Callee必须自己制作副本 优点:与所有人结合。
  4. 通过 rvalue-ref 缺点:无法绑定到左值。如果绑定到const对象,则复制 优点:可以清除传递的参数。
  5. 因此, by-value 几乎总是意味着副本(或至少是一个移动), by-reference 意味着永远不会复制(但对参数的必要限制) ,如果需要转换,所有其余的仅复制 By-const-ref 表示无法修改参数, by-rvalue-ref 表示可以重复使用其资源,这可能会在以后保存副本。< / p>

答案 1 :(得分:2)

  

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

取决于。在所有方面,没有一种方法最适合所有情况。

主要变量:

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

没有一个答案/签名对每个案例都是理想的。

  

std :: string handle-body implementation:是否有任何签名暗示在主叫站点的字符串主体及其支持字符数组的深层副本?

某些实现使用COW(Copy On Write),但在C ++ 11中不再有效。传递值需要一份副本。如果您的库实现了SSO,那么对于短字符串,副本可能很快(=没有堆分配)。

  

C ++ 98与C ++&gt; = 11:这个版本划分的任何一方是否有不同的答案?

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