84669 人學習
152542 人學習
20005 人學習
5487 人學習
7821 人學習
359900 人學習
3350 人學習
180660 人學習
48569 人學習
18603 人學習
40936 人學習
1549 人學習
1183 人學習
32909 人學習
学习是最好的投资!
原因在於優化.先來分析你的程式, a1是一個實例, a2是一個, getTest傳參是傳值那麼會有一個Temp1, getTest又有一個return Temp2. 所以一共應該是四個對象.
但是, 編譯器會有優化, 甚至在你禁止優化的時候也會有一點點優化. 例如getTest的返回值, 本來按照語義是需要調用operator=, 實際上編譯器通常是直接調用CTest1(const CTest1&)這個建構子, 把兩次構造最佳化成1次.
operator=
CTest1(const CTest1&)
你那個程式碼, 把析構函式裡面的cout註解掉, 就會發現只建構了3次. 因為析構函式裡面什麼都沒有的話, 編譯器開啟那個最佳化, 對你的程式碼功能上就沒有任何影響. 但是你開cout的話, 一旦優化掉的話, 程式碼的功能可能就不正確了.
你刪掉析構函式裡面的cout, 用gcc編譯, 加參數-O0 -fno-elide-constructors, 其實還是四個物件.
-O0 -fno-elide-constructors
CTest1 getTestObj(CTest1 obj) { return obj; /* copy */ } int main() { CTest1 a1; // construct CTest1 a2 = /* copy */ getTestObj(a1/* copy */); return 0; }
關於回傳值有一種對編譯器來說省事的方式,叫做回傳值最佳化(RVO - return value optimization)。編譯器會省略一步物件的COPY建構調用,不知道LZ用的什麼編譯器,在gcc(4.8.3)上面是預設開啟的,就是說結果是這樣的:
Constructor of CTest1:0 Copy constructor of CTest1:1 Copy constructor of CTest1:2 //如果去掉注释 就会打印下面三句话 destroy id:1 destroy id:2 destroy id:0
原因在於優化.
先來分析你的程式, a1是一個實例, a2是一個, getTest傳參是傳值那麼會有一個Temp1, getTest又有一個return Temp2. 所以一共應該是四個對象.
但是, 編譯器會有優化, 甚至在你禁止優化的時候也會有一點點優化. 例如getTest的返回值, 本來按照語義是需要調用
operator=
, 實際上編譯器通常是直接調用CTest1(const CTest1&)
這個建構子, 把兩次構造最佳化成1次.你那個程式碼, 把析構函式裡面的cout註解掉, 就會發現只建構了3次. 因為析構函式裡面什麼都沒有的話, 編譯器開啟那個最佳化, 對你的程式碼功能上就沒有任何影響. 但是你開cout的話, 一旦優化掉的話, 程式碼的功能可能就不正確了.
你刪掉析構函式裡面的cout, 用gcc編譯, 加參數
-O0 -fno-elide-constructors
, 其實還是四個物件.關於回傳值有一種對編譯器來說省事的方式,叫做回傳值最佳化(RVO - return value optimization)。編譯器會省略一步物件的COPY建構調用,不知道LZ用的什麼編譯器,在gcc(4.8.3)上面是預設開啟的,就是說結果是這樣的: