ローカル変数への参照を返すのが悪い考えであることは誰もが知っています。ただし、参照を返すことが本当に良い考えであるかどうか、いつそれを行うべきか、いつすべきでないかについての適切なルールを決定できるかどうかは疑問です。
参照を返すことに関する私の問題は、呼び出し元の関数が、責任を負うべきではないオブジェクトの寿命を気にする必要があることです。不自然な例として:
#include <vector>
const int& foo() {
std::vector<int> v = {1, 2, 3, 4, 5};
return v[0];
}
int main(int argc, const char* argv[])
{
const int& not_valid = foo();
return 0;
}
ここで、 はvector
の最後で範囲外になり、foo
その内容を破棄し、その要素への参照を無効にします。vector::operator[]
は要素への参照を返すため、この参照が からさらに返されるとfoo
、 の参照main
がぶら下がっています。const 参照は一時的なものへの参照ではないため、ここでの寿命が延びるとは思いません。
私が言ったように、これは不自然な例であり、おそらく の作者は、参照としてfoo
返そうとするほど愚かではないでしょうv[0]
. ただし、参照を返すために、呼び出し元が所有していないオブジェクトの有効期間を気にする必要があることは簡単にわかります。要素を にプッシュすると、要素がvector
コピーされるため、vector
が責任を負います。参照引数を渡す場合、この問題は存在しません。これは、呼び出し元が続行してオブジェクトを破棄する前に関数が完了することがわかっているためです。
参照を返すと、次のような素敵な配列のような構文が可能になることがわかりますが、次v[0] = 5
のようなメンバー関数を持つことの何が悪いのv.set(index, value)
でしょうか? 少なくともこれで、内部オブジェクトを公開することはありません。参照を返すことによってもパフォーマンスが向上する可能性があることはわかっていますが、RVO、 Named RVO (NRVO) 、および move セマンティクスを使用すると、無視できるか存在しません。
そのため、参照を返すことが本当に安全な状況を想像しようとしましたが、関連する可能性のある所有権セマンティクスのさまざまな順列をすべて理解することはできません。いつこれを行うべきかについて、適切なルールはありますか?
注: s の所有権を処理するより良い方法vector
はスマート ポインターを使用することですが、別のオブジェクトで同じ問題が発生します。スマート ポインターの所有者は誰ですか?