#21 オブジェクトを戻すべき時に参照を戻さない
Effective C++ 4章21項の内容です.
1.ローカルなオブジェクトに対する参照戻し
これも,よく考えるとそのとおりなんですが,テンパってるとやってしまいそうです...何を言っているかというと,例えば次のようなコードがあったとします.
Hoge & localRefReturn() { Hoge hoge; return hoge; } int main() { Hoge hoge = localRefReturn(); return 0; }
ここで,localRefReturnの内部で生成されている hoge の寿命は localRefReturnのスコープ内だけです.なので,localRefReturnを抜けるとhogeのデストラクタが呼ばれて消滅してしまいます.が,,,hogeの参照を返しているので,呼び出し側が消滅したオブジェクトを呼んでしまう可能性があります.このケースでは参照を返すのではなく,コピーして新しい別のオブジェクトを返さないといけません.下記のサンプルコードをコンパイルすると,下記のような GCC のワーニングが出ます.(警告をちゃんと見るのって大事ですね..)
-- Configuring done -- Generating done -- Build files have been written to: /home/koichi/workspace/effective_cpp/chap_4th/build [ 50%] Building CXX object CMakeFiles/chap_4th_21_1.dir/src/chap_4th_21_1.cpp.o /home/koichi/workspace/effective_cpp/chap_4th/src/chap_4th_21_1.cpp: In function ‘Hoge& localRefReturn()’: /home/koichi/workspace/effective_cpp/chap_4th/src/chap_4th_21_1.cpp:27:8: warning: reference to local variable ‘tmp’ returned [-Wreturn-local-addr] Hoge tmp("StackHoge"); ^ [100%] Linking CXX executable chap_4th_21_1 [100%] Built target chap_4th_21_1
2.サンプルコードと実行結果
#include <iostream> #include <string> class Hoge { public: Hoge(std::string name) : m_name(name) { std::cout << "Hoge()" << std::endl; } ~Hoge() { std::cout << "~Hoge()" << std::endl; } Hoge(const Hoge &rhs) : m_name(rhs.m_name) { std::cout << "Hoge(const Hoge &rhs)" << std::endl; } Hoge& operator=(const Hoge &rhs) { std::cout << "Hoge& operator=(const Hoge &rhs)" << std::endl; if (this == &rhs) { return *this; } this->m_name = rhs.m_name; return *this; } void sayName() { std::cout << m_name << std::endl; }; private: std::string m_name; }; Hoge& localRefReturn() { Hoge tmp("StackHoge"); return tmp; } int main(int, char**) { Hoge hoge = localRefReturn(); hoge.sayName(); return 0; }
実行結果
Hoge() ~Hoge() <- 関数 "localRefReturn" を抜けるときに,デストラクタが呼ばれている. Segmentation fault (core dumped) <- すでに消滅したオブジェクトのメソッド sayName() を呼ぼうとしているため,セグフォールト.