Effective C++ 條款31: 千萬不要返回局部對象的引用,也不要返回函數內部用new初始化的指標的引用
這裡可以分為2部分:
1,局部對象:因為返回之後該局部對象已經被釋放了。
2內部new的對象:不能讓外部通過引用來釋放這裡new的對象,別人會很納悶,故會泄漏記憶體。
這裡我要對1進行一下分析:
1 #include <iostream>
2
3 class A
4 {
5 friend std::ostream& operator<<(std::ostream& out, const A &a);
6 public:
7 A(int i) : m_x(i){} A(const A&a) : m_x(a.m_x) { std:: cout << "copy A(" << m_x << ")" << std ::endl;}
8 ~A() { std::cout << "~A()" << std::endl; }
9 private:
10 int m_x;
11 };
12
13 class B
14 {
15 public:
16 B() : m_a(9) {}
17 const A& getA() { return m_a; }
18
19 private:
20 A m_a;
21 };
22
23 std::ostream& operator<<(std::ostream& out, const A &a)
-24 {
25 out << a.m_x;
26 return out;
27 }
28
29 const A & f(int i) { return A(i); }
30
31 int main()
32 {
33 A a = f(2);
34 B b;
35 std::cout << "1:" << f(1) << std::endl;
36 std::cout << "2:" << a << std::endl;
37 std::cout << "3:" << b.getA() << std::endl;
38 return 0;
39 }
編譯警告:
test.cpp: In function ‘const A& f(int)’:
test.cpp:29: warning: returning reference to temporary
告訴我們不能返回1個臨時變數的引用。
注意B::getA()編譯沒有警告,因為其返回的引用為成員對象,外部在調用該方法getA()時,可以保證B::m_a沒有釋放,是有效記憶體。
而調用f(int i)時,會先釋放,我們可以看到第1條列印語句,先輸出了~A(),再輸出
1:-1077671300。有人也許會想為什麼不是
1:~A() -1077671300,這是因為計算運算結果的時候先從右邊的算起了。
由於臨時變數已經釋放,其返回的引用為無效地址,所以取的值也就錯誤了。
而列印第2條,我們發現A a = f(2)中返回給a的對象是正常的,也就是說a的拷貝建構函式的參數是一個有效引用,我認為這裡是編譯器做了最佳化,否則很難解釋解構函式和拷貝建構函式的調用順序。
輸出結果:
~A()
copy A(2)
~A()
1:-1080612004
2:2
3:9
~A()
~A()
綜上所述:
在1個函數中,我們可以返回1個在函數調用結束不會被釋放的對象的引用。比如外部傳入的對象,比如函數所屬類的成員變數等。