按值传递还是按引用传递std::string

105

6
在这个函数中,您打算如何处理字符串? - linuxuser27
@linuxuser27:啊,好问题。答案当然取决于情况...在某些情况下,我只是读取它,在其他情况下,我将其与目录连接起来以构建路径。我相信当我想要修改它时,应该通过值传递,以触发移动构造函数。那么只读情况呢---通过常量引用? - Nordlöw
3个回答

191

根据字符串的使用方式,有多种可能的答案。

1) 如果将字符串用作 ID(不会被修改),最好通过常量引用传递:(std::string const&)

2) 修改字符串但不希望调用方看到这种变化。最好通过值传递:(std::string)

3) 修改字符串并希望调用方看到这种变化。最好通过引用传递:(std::string &)

4) 将字符串发送到函数中,函数的调用者将不再使用该字符串。可以考虑使用移动语义(std::string &&)


Case 3) 只有在 std::string 实现不支持移动语义时才是必要的,对吗? - Nordlöw
1
@Nordlöw 不完全是这样。移动语义很有趣,因为它们移动数据而不是复制数据。在上面的情况下,移动语义将在调用函数中将 std::string 中的 char * 移动到被调用函数中。如果您使用移动语义传递值,则该字符串将不再位于调用函数中,除非您将其传回。请参见上面讨论移动语义的链接。 - linuxuser27
24
#4是不必要的,因为这是在调用者使用std::move并调用按值传递版本来处理自己的参数时可以且应该处理的事情。 - Benjamin Lindley
@BenjaminLindley:请参见http://ideone.com/OYu0Ux。当我直接将字符串字面值传递给具有const std :: string&类型参数的函数时会发生什么?编译器是否在幕后为rvalues创建2个临时std :: string对象并将其分别绑定到两个const引用参数? - Destructor
4
完全没有问题,“&&”可以防止意外以拷贝的方式传递参数。 - emlai
2
@Destructor会从字符串字面量构造一个std::string并将其作为参数传递。然后,它会从该参数复制构造成员字符串。因此,每个参数需要两次分配和两次O(n)数组复制操作。你应该通过值来获取参数,并将它们std::move到成员中。这样就只需要一次分配、一次O(n)数组复制和一次O(1)移动操作。 - emlai

28

查看这个C++11的答案。基本上,如果你传递一个左值,则使用右值引用。

来自这篇文章

void f1(String s) {
    vector<String> v;
    v.push_back(std::move(s));
}
void f2(const String &s) {
    vector<String> v;
    v.push_back(s);
}
"对于左值参数,‘f1’会有一份额外的拷贝传递参数,因为它是按值传递,而‘f2’则有一份额外的拷贝用于调用push_back。所以没有区别;对于右值参数,编译器必须创建一个临时对象'String(L“”)'并将其传递给‘f1’或‘f2’。因为当参数是一个临时对象(即右值)时,‘f2’可以利用移动构造函数,因此现在传递参数的成本对于‘f1’和‘f2’是相同的。”
"这意味着在C++11中,当:

  1. 参数类型支持移动语义- C++11中所有标准库组件都支持
  2. 移动构造函数的成本比复制构造函数更便宜(包括时间和栈使用)。
  3. 函数内部,参数类型将传递到另一个同时支持复制和移动的函数或操作中。
  4. 通常传递临时变量作为参数-您可以组织代码来实现这一点。

时,使用按值传递的方法可以获得更好的性能。"

然而,在C++98中最好通过引用进行传递-这样可以减少复制的数据量。传递const或non-const取决于是否需要更改参数。"

6

2
希望提高速度?传值调用吧 - DanielTuzes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接