学习是最好的投资!
原因在於優化.先來分析你的程式, 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)上面是預設開啟的,就是說結果是這樣的: