C++中函數返回值是一個對象時的問題


問題描述

在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 ...-----

過程解釋:

  1. 在fun函數中,t對象被創建,執行t對象的構造函數(t對象地址為 010FFAC4)
  2. 在fun函數執行return時,會產生一個匿名對象,會執行匿名對象的拷貝構造函數,相當於執行了 Test tmp = t; (匿名對象tmp地址為010FFBD4)
  3. fun函數執行結束,局部變量對象t被釋放,執行t對象的析構函數,fun函數將匿名對象(tmp)返回(返回的是010FFBD4地址的匿名對象)
  4. 在test1函數中,t1對象被創建時 使用了fun函數的返回值,故匿名對象tmp直接變為t1對象(而不是執行拷貝構造函數給t1,就比如執行了Test t1 = Test("xx");)(t1對象的地址即為匿名對象地址 010FFBD4)
  5. test1函數執行完畢后,t1對象被釋放,執行t1的析構函數

在linux平台

使用g++編譯

運行結果:

--------test1 start ...-----
fun start..
我是在fun函數中創建的: 執行了構造函數, 我的地址是 0x7ffe5a2488c0
in fun: 0x7ffe5a2488c0
fun end..
我是在test函數中被創建的對象,我的地址是: 0x7ffe5a2488c0
我是在test函數中被創建的: 執行了析構函數, 我的地址是 0x7ffe5a2488c0
--------test1 end ...-----

過程解釋:

  1. 在fun函數中,t對象被創建,執行t對象的構造函數(t對象地址為 0x7ffe5a2488c0)
  2. 在fun函數結束時,並沒有產生匿名對象,而是將t對象返回(返回的是0x7ffe5a2488c0地址的對象t)
  3. 在test1函數中,t1對象被創建時 使用了fun函數的返回值,故返回對象t直接變為t1對象(而不是執行拷貝構造函數給t1,就比如執行了Test t1 = Test("xx");)(t1對象的地址即為t對象地址 0x7ffe5a2488c0)
  4. test1函數執行完畢后,t1對象被釋放,執行t1的析構函數

結論

  1. 在linux平台上,少產生了一個匿名對象,提高了執行效率
  2. 原本僅在fun函數內有效(局部變量生存周期)的t對象,由於被返回,在test1函數中仍然有效


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM