《Effective c++》第23条:必须返回一个对象时不要试图返回一个引用。所有:
- 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用。
- 也不要返回函数内部用new初始化的智能指针的引用
- 上面两条同样适用于线程:不雅把局部对象的应用、局部指针的引用和局部智能指针的引用传递给一个不知道生命周期的线程。因为可能会出现局部对象被析构的时候,线程还在使用的情况。
必须返回一个对象时,不要试图返回一个引用,很多次遇到这句话,但是在使用的时候,还是没有注意到。返回一个对象的应用,在某种情况下,不会显示出错误,但是为以后代码的出错埋下了伏笔。
我说的某些情况下不会展示出错误,请看下面的例子:
输出都是:#include <iostream> class Test { public: void print() { static int i = 0; std::cout << i++ << std::endl; } }; Test& getTest() { //获取局部对象的引用 Test test; return test; } Test*& getPTest() { //获取局部指针的引用 Test *ptest = new Test; return ptest; } std::shared_ptr<Test>& getShareTest() { //获取局部智能指针的引用 std::shared_ptr<Test> sharePtr(new Test()); return sharePtr; } int main(int argc, char *argv[]) { //以下三个例子分别执行 Test& test1 = getTest(); while(1) { test1.print(); } Test*& test2 = getPTest(); while(1) { test2->print(); } std::shared_ptr<Test> sharePtr = getShareTest(); while(1) { sharePtr->print(); } return 0; }
从上的三个小例子可以看出,局部对象的引用、局部指针的引用、局部智能指针的引用使用都没有问题,也许你会窃喜。0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35(后面省略)
但是只需要修改一点点,就会发现问题:
这次的输出:#include <iostream> class Test { public: Test (int num) : num_(num) {} void print() { static int i = 0; std::cout << num_ << " " << i++ << std::endl; } private: int num_; }; Test& getTest() { //获取局部对象的引用 Test test(10); return test; } Test*& getPTest() { //获取局部指针的引用 Test *ptest = new Test(10); return ptest; } std::shared_ptr<Test>& getShareTest() { //获取局部智能指针的引用 std::shared_ptr<Test> sharePtr(new Test(10)); return sharePtr; } int main(int argc, char *argv[]) { //以下三个例子分别执行 Test& test1 = getTest(); while(1) { test1.print(); } Test*& test2 = getPTest(); while(1) { test2->print(); } std::shared_ptr<Test> sharePtr = getShareTest(); while(1) { sharePtr->print(); } return 0; }
只输出一次正确的结果,多次执行的结果并不相同,怎么回事呢?这时候你会想到传进去的10存在哪里?栈上?那函数结束,出栈?对的!函数执行结束的时候,局部变量的作用域结束,局部变量被析构,内容出栈,所以输出的内容是垃圾值。10 0 -1239546272 1 -1239546272 2 -1239546272 3 -1239546272 4 -1239546272 5 -1239546272 6 -1239546272 7 -1239546272 8 -1239546272 9 -1239546272 10 -1239546272 11 -1239546272 12 -1239546272 13 -1239546272 14 -1239546272 15 -1239546272 16 -1239546272 17 -1239546272 18 -1239546272 19 -1239546272 20 -1239546272 21(后面省略)