標籤:

C++返回類型為類類型的函數返回的臨時變數賦值及生存周期?

編譯環境:win64 vs2010 控制台程序

類及函數定義如下:

class cat

{

public:

int age;

cat(void)

{

cout&<&<"void構造函數"&<&

}

cat(int _age)

:age(_age)

{

cout&<&<"int構造函數"&<&

}

cat(const cat _cat)

:age(_cat.age)

{

cout&<&<"複製構造函數"&<&

}

cat operator=(const cat _cat)

{

cout&<&<"賦值操作符"&<&

age = _cat.age;

return *this;

}

~cat()

{

cout&<&<"析構函數"&<&

}

};

cat show(cat _cat)

{

return _cat;

}

問題1:

在main()函數中有如下代碼:

cat cat1; cat1.age = 11;

cat cat2; cat2.age = 12;

cat cat3 = show(cat2) = cat1; // ok cat3.age=11;

show(cat2).age = 13; // error C2106: 「=」: 左操作數必須為左值

通過查找資料,show()函數返回的臨時變數為右值,不可以直接更改成員變數,但是可以調用成員函數,第一條語句通過調用賦值操作符改變了臨時變數。理論上結果就應該是這樣。但是,如果注釋掉cat類中的所有構造函數、賦值操作符、析構函數,再次執行:

int age1 = show(cat2).age = 13; // ok, age11=13.

可以編譯通過,不明白為什麼把這些函數注釋掉就可以了,請各位解答。

問題2:

執行語句: show(cat1);

輸出以及我認為的意義應該是:

***************************************************

複製構造函數 //使用實參初始化形參

複製構造函數 //使用形參初始化函數返回值臨時變數

析構函數 //形參析構

析構函數 //函數返回值臨時變數析構。

***************************************************

執行語句:cat cat3 = show(cat1);

輸出以及我認為的意義應該是:

***************************************************

複製構造函數 //使用實參初始化形參

複製構造函數 //使用形參初始化函數返回值臨時變數

析構函數 //形參析構

***************************************************

通過對比,我們發現當使用函數返回值初始化cat3時,少執行了一次析構函數,應該是函數返回值臨時變數未進行析構。並且使用函數返回值初始化cat3時並沒有再次調用複製構造構造函數,就像是給沒有名字的函數返回值臨時變數賦予了一個名字cat3並延長了生存周期。

再執行語句:cat cat3 = show(cat1) = cat2;

輸出以及我認為的意義應該是:

***************************************************

複製構造函數 //使用實參初始化形參

複製構造函數 //使用形參初始化函數返回值臨時變數

析構函數 //形參析構

賦值操作符 //cat2賦值給臨時變數

複製構造函數 //使用被重新賦值的臨時變數初始化cat3

析構函數 //臨時變數析構。

***************************************************

對比上一條語句,如果給臨時變數重新賦值之後,再用其初始化cat3,臨時變數相當於一個獨立的對象,會調用複製構造函數初始化cat3然後析構,生命周期結束。通過查找資料,我知道函數返回值臨時變數存儲於main()棧幀中,會分配臨時變數對象所需要的存儲空間,且作用域為mian()函數塊。但是為什麼會出現這種現象,臨時變數的生存周期到底是怎樣的?請各位大神解答。


1.VC++ Bug.
2.VC++在「誤導」你,如:cat cat3 = show(cat1);

這裡不僅有你說的:

複製構造函數 //使用實參初始化形參

複製構造函數 //使用形參初始化函數返回值臨時變數

析構函數 //形參析構

還有一個複製構造函數和析構函數的調用,但是你若在Clang++ / G++下,你可以通過-fno-elide-constructors選項來觀測這種行為:

-fno-elide-constructors
The C++ standard allows an implementation to omit creating a
temporary which is only used to initialize another object of the
same type. Specifying this option disables that optimization,and
forces G++ to call the copy constructor in all cases.

建議更換編譯器,並且開啟-fno-elide-constructors選項來進行理解。


推薦閱讀:

求反函數清晰的定義。?
是不是任意曲線都有其對應函數公式?
基於阿里雲Serverless架構下函數計算的最新應用場景詳解

TAG:函數 | CC |