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"));
} ///:~
は、上記の例を考えると、我々は参照渡し変数を変更しませんでした、どちらも我々は、これら2つの方法の間に差がないsame.Since各方法の通過による値variable.The出力を変更することができ、なぜCは、両方の方法をサポートする++のですか?
感謝ます。
解決
2つの違いはあります。次のことを考えてみます:
#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
参照が関数内CONSTされているのでだけが、referandが他の参照(それへの複数の参照またはポインタを有する1つのオブジェクトの状況が「エイリアシング」と呼ばれる)を介して変更することができないことを意味するものではありません。呼び出しが行われた後、基準の場合には、オブジェクトが変更される可能性があり - 従ってconst参照を渡し、および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の指定子の、あなたはそれを変更することはできません。これは、「保護」の一種です。
あなたのオブジェクトでもAで変更することができます可変のメンバーを、含まれている可能性がありconst参照
outputStringByRef
を使用すると、変数はあなたが長いoutputStringByRef
がそれを必要とするほどのために生きていると変わらへの参照を渡していることを確認する必要があります。 outputStringByVal
で死ぬまたは範囲から抜け出すことができ渡される変数と関数が持っているコピーはまだ大丈夫です。
関数内の文字列を変更することができるという点では(ほとんど)に違いはありません。しかし渡されているものの面で大きな違いがあります。 const mystring &ss
の過負荷は、文字列へのconst参照を取ります。それはそれを変更することはできませんが、それは同じメモリビーイングが取り上げています。文字列が長い場合、これは大きな要因になることができます(文字列はコピーを使用して実装されていないと仮定すると-on-書き込みを)。 const mystring ss
フォームは、文字列のコピーを作っているので、異なるメモリがアドレス指定されます。
実際const mystring &ss
フォーム のconst_cast<mystring&>
を使用した場合、文字列を変更することができます
あなたがコピーできないオブジェクトを印刷したい想像します:
Thread th;
// ...
cout << th; // print out informations...
参照バージョンは、スレッドをコピーしませんが、th
のアドレスを取得し、それにエイリアスを作成します。 (一つの追加のスレッドが、その後があるだろう?)が、コピーは、そのようなオブジェクトのsensefulないかもしれません。
それはあなたがのを考えるのに役立つかもしれオブジェクトをコピーのようにのオブジェクトをクローニングの。それは暗黙的にオブジェクトが示さクローンを作成し、それの全体のコピーを持っている意味は - C ++で上th
をコピーすると、単にJavaのと同じオブジェクトに別のハンドルを持っているという意味ではありません。質問は「なぜJavaがObject.clone
と参照のコピーの両方をサポートしていますか?」に似ているので、 - 両方の異なる目的を持っています。
そして、すべての後、あまりにもパフォーマンスの問題があります。あなたは、リソース空腹のオブジェクトの周りに何かを渡す毎回コピーする必要はありません。