F(常量字符串&)和f(常量字符串)有何区别?
-
21-09-2019 - |
题
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"));
} ///:~
考虑到上述示例,我们无法修改的通按引用变量,我们也不可以修改的每个方法通过噪声值variable.The输出的是same.Since在这两个方法之间没有区别,为什么C ++支持这两种方法?
感谢。
解决方案
有两者之间的差。考虑以下几点:
#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);
}
输出:
red
blue
仅仅因为一个参考是在函数内部常量,并不意味着该referand不能通过其他参考被修改(的具有多个引用或指针给它的一个对象被称为“混叠”的情形)。因此,存在通过const引用,并通过一个常数值之间的不同 - 在参考的情况下,该呼叫由后的对象可能会改变。在该值的情况下,被叫方有一个专用副本,它也不会改变。
由于他们做不同的事情,C ++让你选择你想要的。
有绩效的后果无论哪种方式 - 当你路过值,副本要作出,它的价格。但是,编译器就知道,只有你的函数都不可能有该副本,这可能会允许其他的优化的任何引用。 ProcessStringByRef无法加载字符串的内容打印到callback()
又回来了。 ProcessStringByValue可以,如果编译器认为这样做比较快。
通常你所关心的副本,而不是指令执行顺序,因为通常情况下副本的方式更加昂贵。所以通常情况下,你通过引用传递,其中有可能是不平凡的复制对象。但走样的可能性,有时有表现的确严重后果,防止即使没有走样实际发生一定的优化。这就是为什么“严格别名规则”的存在,并在C99的restrict
关键字。
其他提示
f(const string&)
通过const
参考取串:f
is直接通过引用传递的字符串对象上操作:不存在所涉及的副本。 const
防止修改原始对象虽然。
f(const string)
采用一个字符串值,这意味着f
给出原始字符串的副本。即使跌落const
,按值传递时,对字符串中的任何修改都将丢失时f
回报。
我并不确切地知道你的“为什么C ++支持这两种方法?”的意思。它适用只是一般的重载规则。
f(string s)
传值字符串s,换句话说,它创建一个副本,并与传递的字符串的值进行初始化。在副本中的任何改变,都不会传播给你传递给调用函数的原始字符串。
在f(const string s)
const为多余的,因为不能改变无论如何原始值。
在f(const string& s)
不是字符串不被复制,但传递到它的一个参考。当你有一个大的对象,这样的“传递的价值”能够产生的开销这通常是(这就是为什么C ++支持这两种方法)。按引用传递意味着你可以改变你通过“大”对象的值,但由于限定符const,你不能修改它。这是一种“保护”。
你的对象可能包含一个可变构件,其可甚至与被修改const引用
使用outputStringByRef
你必须确保变量你传递的引用,仍然活着,并没有改变,只要outputStringByRef
需要它。与outputStringByVal
您可以通过死亡或走出范围的变量和函数具有复制仍未确定。
有(几乎)在能够给该函数内修改字符串方面没有差异。但是,有在被传递什么样的条件有很大的区别。所述const mystring &ss
重载采用常量引用的字符串。虽然不能修改它,它正在处理相同的内存。如果字符串长度这可能是一个很大的因素(假设这个字符串没有使用复制来实现-on写)。所述const mystring ss
形式使字符串的副本,所以不同的存储器将得到解决。
其实const mystring &ss
形式的可能的修改字符串,如果使用了const_cast<mystring&>
- 虽然我不建议在这里
假设你要打印不能被复制的对象:
Thread th;
// ...
cout << th; // print out informations...
在参考版本不会复制线程,但将采取th
的地址,并创建一个别名给它。另一版本将尝试复制由值传递当线程 - 但复制可能不适用于这样的目的是senseful(?会有一个额外的螺纹然后)
它可以帮助你思考的的复制对象的作为的克隆对象的。复制th
以上C ++并不仅仅意味着有另一个手柄相同的对象在Java中 - 它意味着隐式克隆对象表示,有它的整个副本。所以,问题是类似“为什么Java支持的引用既Object.clone
和复制?” - 都有不同的目的。
再有就是性能的问题也一样,毕竟。你不想给每一位你传递的资源饥饿物体周围的东西一次复制。