問題描述
在C++程序中,一個函數返回值是一個對象時,返回的是函數內部的局部變量本身,
還是會產生一個中間對象(匿名對象)呢?
經過測試,在win平台和Linux平台效果不同
代碼如下
//
// Created by YANHAI on 2019/5/28.
//
#include <iostream>
using namespace std;
class Test {
public:
Test(const char *name)
{
this->name = name;
printf("%s: 執行了構造函數, 我的地址是 %p\n", name, this);
}
Test(const Test &obj)
{
this->name = obj.name;
printf("%s: 執行了拷貝構造函數,我的地址是 %p,拷貝來自%s %p\n",
name.c_str(), this, obj.name.c_str(), &obj);
}
~Test()
{
printf("%s: 執行了析構函數, 我的地址是 %p\n", name.c_str(), this);
}
public:
string name;
};
Test fun()
{
Test t("我是在fun函數中創建的");
printf("in fun: %p\n", &t);
return t;
}
void test1()
{
// 這里t1對象就是fun函數里面創建的?
cout << "fun start.." << endl;
Test t1 = fun();
cout << "fun end.." << endl;
t1.name = "我是在test函數中被創建的";
printf("我是在test函數中被創建的對象,我的地址是: %p\n", &t1);
}
int main()
{
cout << "--------test1 start ...-----" << endl;
test1();
cout << "--------test1 end ...-----" << endl;
return 0;
}
測試過程
在win平台
使用VS2019編譯並運行
運行結果:
--------test1 start ...-----
fun start..
我是在fun函數中創建的: 執行了構造函數, 我的地址是 010FFAC4
in fun: 010FFAC4
我是在fun函數中創建的: 執行了拷貝構造函數,我的地址是 010FFBD4,拷貝來自我是在fun函數中創建的 010FFAC4
我是在fun函數中創建的: 執行了析構函數, 我的地址是 010FFAC4
fun end..
我是在test函數中被創建的對象,我的地址是: 010FFBD4
我是在test函數中被創建的: 執行了析構函數, 我的地址是 010FFBD4
--------test1 end ...-----
過程解釋:
- 在fun函數中,t對象被創建,執行t對象的構造函數(t對象地址為 010FFAC4)
- 在fun函數執行return時,會產生一個匿名對象,會執行匿名對象的拷貝構造函數,相當於執行了 Test tmp = t; (匿名對象tmp地址為010FFBD4)
- fun函數執行結束,局部變量對象t被釋放,執行t對象的析構函數,fun函數將匿名對象(tmp)返回(返回的是010FFBD4地址的匿名對象)
- 在test1函數中,t1對象被創建時 使用了fun函數的返回值,故匿名對象tmp直接變為t1對象(而不是執行拷貝構造函數給t1,就比如執行了Test t1 = Test("xx");)(t1對象的地址即為匿名對象地址 010FFBD4)
- test1函數執行完畢后,t1對象被釋放,執行t1的析構函數
在linux平台
使用g++編譯
運行結果:
--------test1 start ...-----
fun start..
我是在fun函數中創建的: 執行了構造函數, 我的地址是 0x7ffe5a2488c0
in fun: 0x7ffe5a2488c0
fun end..
我是在test函數中被創建的對象,我的地址是: 0x7ffe5a2488c0
我是在test函數中被創建的: 執行了析構函數, 我的地址是 0x7ffe5a2488c0
--------test1 end ...-----
過程解釋:
- 在fun函數中,t對象被創建,執行t對象的構造函數(t對象地址為 0x7ffe5a2488c0)
- 在fun函數結束時,並沒有產生匿名對象,而是將t對象返回(返回的是0x7ffe5a2488c0地址的對象t)
- 在test1函數中,t1對象被創建時 使用了fun函數的返回值,故返回對象t直接變為t1對象(而不是執行拷貝構造函數給t1,就比如執行了Test t1 = Test("xx");)(t1對象的地址即為t對象地址 0x7ffe5a2488c0)
- test1函數執行完畢后,t1對象被釋放,執行t1的析構函數
結論
- 在linux平台上,少產生了一個匿名對象,提高了執行效率
- 原本僅在fun函數內有效(局部變量生存周期)的t對象,由於被返回,在test1函數中仍然有效