一時オブジェクトの寿命
先輩にバグじゃないの?と指摘されたコード。
class MyString { public: MyString(); MyString(const std::string& s); : }; extern const std::string& GetName(int idx); int main() { for (int i = 0; i < N; ++i) { const MyString& s = GetName(i); // この後、forのスコープ内で文字列 s を使うのは安全か? } return 0; }
このコードは、以前、レガシーな std::string を使ったコードを国際化対応した文字列クラスに一括置換したときに生じたものだ。まだプロダクションには使われていないが、一瞬、嫌な汗をかいた。結論から言うとこれは合法だった。コンパイラも完全にスルーしていたので気付かず。
何が起こっているかというと、GetName() で std::string の参照が返った後、MyString の変換コンストラクタ MyString(const std::string&) が呼ばれ、一時オブジェクトが作られる。一時オブジェクトをconst参照で受けた場合、一時オブジェクトはconst参照に束縛されるというルールがあり、const参照変数のスコープまで延命される。したがってfor文のスコープ内で使うことができる。
まぁ、参照で受けてコピーを作らないという意図も叶っておらず、単にややこしいだけなので、早々に直したほうが良いだろう。