c c 高階之愛恨交織的臨時物件 一 出生和死亡

2021-07-30 19:11:32 字數 3546 閱讀 3741

首先問乙個問題,什麼是c++中的臨時物件呢?

有時候,在求表示式值期間,編譯器必須建立臨時物件(temporary object)。像其他任何物件一樣,它們需要儲存空間,並且必須能夠構造和銷毀。區別是從來看不到它們——編譯器負責決定它們的去留以及它們存在的細節。(c++程式設計思想第一卷(第一版)183頁)

從上面一段話中,我們能夠窺得臨時物件的一些基本特徵,那麼它的定義又是怎樣呢?c++中,我們說,對於一切非顯示定義和生成的物件均為臨時物件。

現在我們終於知道什麼是臨時物件了。那麼你可能接著要問了,既然編譯器負責它們的存活去留,我們為什麼還要關注臨時物件呢?好問題,但我們先耐住性子接著往下看,我將逐一的為您分析講解。

一般的來說,在如下的幾種情況中會產生臨時物件:

如果建構函式只接受乙個實參,則它實際上定義了轉換為此類型別的隱式轉換機制,有時我們把這種建構函式稱作轉換建構函式(converting constructor)。(c++ primer中文版(第五版)第263頁)

如果定義乙個建構函式,這個建構函式能把另一型別物件(或引用)作為它的單個引數,那麼這個建構函式允許編譯器執行自動型別轉換。(c++程式設計思想第一卷(第一版)296頁)

看下面**:

#include 

class ctest

~ctest()

};void func(ctest);

void func(ctest){}

int main()

編譯並執行,結果如下:

從上圖可以看到,我們確實構造了乙個ctest臨時物件並且析構了。但是,有時候這種隱式轉換並不是我們想要的,所以可以對建構函式加上explicit關鍵字。關於這方面的內容,感興趣的讀者們可以去自行查閱資料。

在我們學習c語言的時候,老師們一定都講過c語言的函式傳參方式是傳值方式(pass-by-value

#include

class ctest

ctest(const ctest& other)

~ctest()

};void func(ctest);

int main()

void func(ctest){}

// g++ -std=c++11 ***.cpp -o ***

// 這裡採用的gcc版本為gcc 5.3.1編譯並執行以上**,結果如下:

從上面的結果來看,在按值傳參的時候,編譯器呼叫了拷貝建構函式構造了乙個臨時物件,並在離開void func(ctest)函式的作用域時析構。

與按值傳參一樣,函式按值返回乙個自定義型別的物件時,同樣會呼叫拷貝建構函式建立乙個臨時物件。具體可參考下列**。

#include 

#include

using

namespace

std;

class ctest

ctest(const ctest& other)

~ctest()

};ctest func();

int main()

ctest func()

// !!!注意,這裡是在visual studio 2013 debug模式下編譯執行的,不同的編譯器出來的結果可能不一樣。原因後面有介紹。

開啟cmd,在console下用命令列執行上程式,結果如下:

我們來分析下上述**。在main()函式中,在表示式func()處建立了乙個臨時物件,用來存放func()函式中返回的物件。在func()函式中,首先構造了test物件,然後呼叫拷貝建構函式將test物件拷貝外部臨時物件的儲存單元內,然後test物件被析構。

當建立乙個匿名的非堆(non-heap)物件,這時候也會產生臨時物件。

執行如下**:

可以看到,我們這裡確實產生了乙個臨時物件。

考慮以下**

#include 

#include

int main()

執行結果如下:

在這裡我們輸出的實際上是由表示式str1 + str2得到的臨時物件的值。

通過上面的表述,我們已經知道了何時會產生臨時物件了。那麼,臨時物件什麼時候死亡呢?畢竟,我們要是用了個已死的物件或者資源,那就哭都哭不出來了…

在c++中規定了,在生成臨時物件的最大表示式結束處即是臨時物件的析構處(eos,end of statement),也就是臨時物件的死亡時刻。

在1.5中的表示式求值的**中,str1+str2生成的臨時物件會在最大表示式結束處析構,在這裡的最大表示式為printf()函式呼叫,即在printf()函式呼叫完成後才析構str1 + str2生成的臨時物件。

將1.5中的**稍稍變形,改為如下:

#include 

#include

int main()

會發生什麼?不知道!天知道。通過上面的分析我們可以知道,在printf()函式呼叫之前,由表示式str1 + str2建立的臨時物件就已經被析構了,而標準庫的實現上是肯定在析構的時候就把所有占用的資源都釋放了的。(不排除某些不太合格的程式設計師根本就不去管資源的釋放,那樣在當下的情境下,反而不會出問題)。所以,這時候我們的指標p就成了懸掛指標了,而對乙個懸掛指標的操作,想想就令人害怕不是麼?

總結:這一小節介紹了臨時物件的出生和死亡,下面我們還會介紹關於臨時變數的一些用法、性質和隱藏的坑還有右值、左值、右值引用、移動語義等與臨時變數密切相關的內容。敬請期待 :)

參考資料:

《c++程式設計思想第一卷》

《c++ primer 中文版第五版》

c c 高階之路

c c 從入門到高手所有必備pdf書籍收藏,喜歡的朋友支援下吧 c c和指標 pdf高畫質版 c程式語言 完美中文版pdf the c programming language 英文原版 c的缺陷與陷阱 pdf高畫質版 你必須知道的495個c語言問題 完美pdf c專家程式設計 高畫質版pdf 中英...

C C 高階語法 引用

引用就是物件的另乙個名字。在實際程式中,引用主要用作函式的形參。引用是一種復合型別,通過在變數名前新增 符號來定義。引用必須用與該引用同型別的物件初始化。int var 12 int num var 沒問題,將int型的引用指向int型的物件 char ch var 錯誤,char型別的物件不能指向...

迷宮問題(高階)C C

利用廣度優先搜尋來解決迷宮中的最短路徑,需要把佇列稍微做下調整,博主用的順序佇列,也可以用鏈式,鏈式搜尋起來方便些。之前看到有校友用dfs來解決的,但是相對來說演算法複雜度要高些,因為dfs一般用來解決所有路徑數目問題。typedef structsqqueue 直接甩 include includ...