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架構下函數計算的最新應用場景詳解