C++ f(const string &) 和 f(const string) 之间有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1961028/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Any differences between f(const string &) and f(const string )?
提问by Jichao
class mystring {
friend ostream& operator<<(ostream &out, const mystring ss) {
out << ss.s;
return out;
}
private:
string s;
public:
mystring(const char ss[]) {
cout << "constructing mystring : " << ss << endl;
s = ss;
}
};
void outputStringByRef(const mystring &ss) {
cout << "outputString(const string& ) " << ss << endl;
}
void outputStringByVal(const mystring ss) {
cout << "outputString(const string ) " << ss << endl;
}
int main(void) {
outputStringByRef("string by reference");
outputStringByVal("string by value");
outputStringByRef(mystring("string by reference explict call mystring consructor"));
outputStringByVal(mystring("string by value explict call mystring constructor"));
} ///:~
Considering the above example,we could not modify the pass-by-reference variable,neither could we modify the pass-by-value variable.The output of each methods is same.Since there is no difference between these two method,why do C++ support both methods?
考虑上面的例子,我们不能修改pass-by-reference变量,也不能修改pass-by-value变量。每种方法的输出都是一样的。既然这两种方法没有区别,为什么C++支持这两种方法吗?
thanks.
谢谢。
回答by Steve Jessop
There is a difference between the two. Consider the following:
两者之间存在差异。考虑以下:
#include <iostream>
#include <string>
using std::string;
string g_value;
void callback() {
g_value = "blue";
}
void ProcessStringByRef(const string &s) {
callback();
std::cout << s << "\n";
}
void ProcessStringByValue(const string s) {
callback();
std::cout << s << "\n";
}
int main() {
g_value = "red";
ProcessStringByValue(g_value);
g_value = "red";
ProcessStringByRef(g_value);
}
Output:
输出:
red
blue
Just because a reference is const inside a function, doesn't mean that the referand can't be modified via other references (the situation of one object having multiple references or pointers to it is called "aliasing"). Thus there is a different between passing a const reference, and passing a const value - in the case of the reference, the object might change after the call is made. In the case of the value, the callee has a private copy, which will not change.
仅仅因为函数内部的引用是常量,并不意味着不能通过其他引用修改引用对象(一个对象具有多个引用或指向它的指针的情况称为“别名”)。因此,传递 const 引用和传递 const 值之间存在差异 - 在引用的情况下,对象可能会在调用后发生变化。在值的情况下,被调用者有一个私有副本,不会改变。
Since they do different things, C++ lets you choose which you want.
因为它们做不同的事情,所以 C++ 让你选择你想要的。
There are consequences for performance either way - when you pass by value, a copy has to be made, which costs. But the compiler then knows that only your function can possibly have any references to that copy, which might allow other optimisations. ProcessStringByRef cannot load the contents of the string for printing until callback()
has returned. ProcessStringByValue can, if the compiler thinks doing so is faster.
无论哪种方式都会对性能产生影响 - 当您通过值传递时,必须制作副本,这会产生成本。但是编译器然后知道只有您的函数可能有对该副本的任何引用,这可能允许其他优化。ProcessStringByRefcallback()
在返回之前无法加载用于打印的字符串内容。ProcessStringByValue 可以,如果编译器认为这样做更快。
Usually you care about the copy, not the order of execution of instructions, because usually the copy is way more expensive. So usually, you pass by reference where possible for objects that are non-trivial to copy. But the possibility of aliasing sometimes has really serious consequences for performance, by preventing certain optimisations even though no aliasing actually occurs. That's why "strict aliasing rules" exist, and the restrict
keyword in C99.
通常你关心的是副本,而不是指令的执行顺序,因为通常副本的成本更高。因此,通常情况下,您会尽可能通过引用传递不易复制的对象。但是,即使实际上没有发生混叠,也会阻止某些优化,因此混叠的可能性有时会对性能产生非常严重的影响。这就是为什么存在“严格的别名规则”以及restrict
C99 中的关键字的原因。
回答by Gregory Pakosz
f(const string&)
takes string by const
reference: f
is operating directly on the string object passed by reference: there is no copy involved. const
prevents modifications to the original object though.
f(const string&)
通过const
引用获取字符串:f
直接对通过引用传递的字符串对象进行操作:不涉及复制。const
防止修改原始对象。
f(const string)
takes a string value, which means f
is given a copy of the original string. Even if you drop const
, when passing by value, any modification to the string is lost when f
returns.
f(const string)
接受一个字符串值,这意味着f
给出原始字符串的副本。即使您 drop const
,在按值传递时,对字符串的任何修改在f
返回时也会丢失。
I don't know exactly what you mean by "why do C++ support both methods?". It's just general overloading rules that apply.
我不知道您所说的“为什么 C++ 支持这两种方法?”的确切含义。这只是适用的一般重载规则。
回答by Salv0
f(string s)
pass by value the string s, in other words it creates a copy and initializes it with the value of the string you pass. Any change to the copy, will not be propagated to the original string you passed to call the function.
In f(const string s)
const is redundant because you can't anyway change the original value.
f(string s)
按值传递字符串 s,换句话说,它创建一个副本并使用您传递的字符串的值对其进行初始化。对副本的任何更改都不会传播到您传递给调用函数的原始字符串。在f(const string s)
const 中是多余的,因为您无论如何都无法更改原始值。
In f(const string& s)
instead the string is not copied but you pass a reference to it. This is usually done when you have a large object so the "pass-by-value" can produce an overhead ( that's why c++ supports both methods ). Passing by reference means that you can change the value of the "large" object you pass, but because of the const specifier, you can't modify it. It's a sort of "protection".
在f(const string& s)
不是字符串是不可复制的,但你传递给它的参考。这通常在您有一个大对象时完成,因此“按值传递”会产生开销(这就是为什么 c++ 支持这两种方法)。通过引用传递意味着你可以改变你传递的“大”对象的值,但是因为const说明符,你不能修改它。这是一种“保护”。
回答by josefx
回答by shoosh
With outputStringByRef
you must ensure that the variable you're passing a reference to remains alive and unchanged for as long as outputStringByRef
needs it. with outputStringByVal
the variable you passed can die or get out of scope and the copy that the function has is still ok.
随着outputStringByRef
你必须确保变量你传递的引用,但仍然活着,并没有改变,只要outputStringByRef
需要它。与outputStringByVal
您可以通过死亡或得到的范围之变量和函数具有复制仍未确定。
回答by philsquared
There is (almost) no difference in terms of being able to modify the string within the function. However there is a big difference in terms of what is being passed. The const mystring &ss
overload takes a const reference to the string. Although it cannot modify it, it is the same memory being addressed. If the string is long this can be a big factor (assuming the string is not implemented using copy-on-write). The const mystring ss
form is making a copy of the string, so different memory will be addressed.
在能够修改函数内的字符串方面(几乎)没有区别。但是,在传递的内容方面存在很大差异。的const mystring &ss
重载采用常量引用的字符串。虽然它不能修改它,但它是被寻址的同一个内存。如果字符串很长,这可能是一个很大的因素(假设字符串不是使用copy-on-write 实现的)。该const mystring ss
表单正在制作字符串的副本,因此将寻址不同的内存。
Actually the const mystring &ss
form couldchange the string, if a const_cast<mystring&>
was used - although I wouldn't recommend that here.
实际上,如果使用了 a,const mystring &ss
表单可以更改字符串const_cast<mystring&>
- 尽管我不建议在这里这样做。
回答by Johannes Schaub - litb
Imagine you want to print an object that can't be copied:
想象一下,您要打印一个无法复制的对象:
Thread th;
// ...
cout << th; // print out informations...
The reference version will not copy the thread, but will take the address of th
and create an alias to it. The other version would try to copy the thread when passing by value - but copying may not be senseful for such an object (would there be one additional thread then?).
参考版本不会复制线程,但会获取它的地址th
并为其创建别名。另一个版本会在按值传递时尝试复制线程 - 但复制对于这样的对象可能没有意义(然后会有一个额外的线程吗?)。
It may help you to think of copy an objectas cloning an object. Copying th
above in C++ does not merely mean to have another handle to the same object as in Java - it does mean to implicitly clone the object denoted, and have a whole copy of it. So the question is similar to "Why does Java support both Object.clone
and copying of references?" - both have different purposes.
它可以帮助您将复制对象视为克隆对象。th
在 C++ 中复制上面的内容不仅仅意味着像在 Java 中那样对同一个对象有另一个句柄 - 它确实意味着隐式克隆所表示的对象,并拥有它的完整副本。所以这个问题类似于“为什么 Java 支持Object.clone
和复制引用?” - 两者都有不同的目的。
And then there is a matter of performance too, after all. You don't want to copy each and every time you pass something around for resource hungry objects.
毕竟,还有一个性能问题。您不想每次为资源匮乏的对象传递一些东西时都进行复制。