C++ 臨時對象

臨時對象通常產生於3種情況:
1、類型轉換
2、按值傳遞
3、按值返回


  1. 類型轉換

通常是爲了讓函數調用成功而產生的臨時對象:傳遞某對象給一個函數,而其類型與它綁定的參數類型不同。
例如:

void test(const string& str);
char buffer[] = "buffer";
test(buffer);//此刻發生類型轉換

編譯器類型轉換:產生一個類型爲string的臨時對象,該對象以buffer爲參數調用string constructor,當test函數返回時,臨時對象會自動銷燬。
注意:對於引用(reference)參數而言,只有當對象被傳遞給一個reference-to-const參數時,轉換才發生。如果對象參數傳遞給一個reference-to-non-const對象,則不會發生轉換。
例如:

void upper(string& str);
char buffer[] = "buffer";
test(buffer);//編譯出錯
  1. 按值傳遞:通常是爲了讓函數調用成功而產生臨時對象。
    例如:
void foo(X x0);
X xx;
foo(xx);

此時編譯器產生的僞代碼:

//編譯器產生的臨時對象
X _temp0;
//編譯器對拷貝構造的調用
_temp0.X::X(xx);
foo(_temp0);

又如例:

class CTemp
{
public:
    int a;
    int b;
    CTemp(CTemp& t){cout << "copy function " << endl; a = t.a; b = t.b;};
    CTemp(int m = 0, int n = 0);
    virtual ~CTemp(){};
    int GetSum(CTemp ts);
};
CTemp::CTemp(int m, int n)
{
    cout << "construct function " << endl;
    a = m;
    b = n;
    cout << a << endl;
    cout << b << endl;
}
int CTemp::GetSum(CTemp ts)
{
    int tmp = ts.a + ts.b;
    ts.a = 100;
    return tmp;
}
void main()
{
    CTemp tm(10, 20);
    cout << tm.GetSum(tm) << endl;
    cout << tm.a << endl;
}

這裏寫圖片描述
1,調用拷貝構造函數來創建一個副本爲GetSum函數體內所用。
2,在GetSum函數體內對tm副本進行的修改並沒有影響到tm本身。

int CTemp::GetSum(CTemp& ts)
{
    int tmp = ts.a + ts.b;
    ts.a = 1000;     //此時通過ts這個引用參考(refer to)對象本身
    return tmp;
}

這裏寫圖片描述
通過引用,減少了一次臨時對象的創建。

如程序改爲:

void main()
{
    CTemp tm(10, 20),sum;
    sum = 1000;      ////調用CTemp(int m = 0,int n = 0)構造函數
    cout << tm.GetSum(sum) << endl; 
}

這裏寫圖片描述
輸出調用了3次構造函數:sum = 1000. 1000和sum類型不符,但編譯器爲了通過編譯以1000爲參數調用構造函數創建了臨時對象。
解決方法:

void main()
{
    CTemp tm(10, 20);
    CTemp sum = 1000;
    cout << tm.GetSum(sum) << endl;
}

只作了稍稍改動,就減少了一次臨時對象的創建。
1,此時的“=”號由原本的賦值變爲了構造。
2,對Sum的構造推遲了。當我們定義CTmep sum時,在main的棧中爲sum對象創建了一個預留的空間。而我們用1000調用構造時,此時的構造是在爲sum預留的空間中進行的。因此也減少了一次臨時對象的創建。

  1. 函數返回一個對象
    當函數需要返回一個對象,會在棧中創建一個臨時對象,存儲函數的返回值。、
    例如:
class CTemp
{
public:
    int a;
    CTemp(CTemp& t)
    {
        cout << "Copy ctor" << endl;
        a = t.a;
    }
    CTemp& operator=(CTemp& t)
    {
        cout << "Assignment copy ctor" << endl;
        a = t.a;
        return *this;
    }
    CTemp(int m = 0);
    virtual ~CTemp(){};
};
CTemp::CTemp(int m)
{
    cout << "Construct function" << endl;
    a = m;
}
CTemp Double(CTemp& ts)
{
    CTemp tmp;
    tmp.a = ts.a * 2;
    return tmp;
}
void main()
{
    CTemp tm(10), sum;
    sum = Double(tm);
    cout << sum.a << endl;
}

這裏寫圖片描述
對於 sum = Double(tm);語句生成了兩個對象:
1、創建一個tmp臨時對象 CTmp tmp;
2、將tmp對象返回,返回過程中調用Copy cotr創建一個返回對象:return tmp;
3、將返回結果通過調用賦值拷貝函數,賦給sum:sum = 函數返回值;//該步沒有創建對象
解決方案:


void main()
{
    CTemp tm(10);
    CTemp sum = Double(tm);
    cout << sum.a << endl;
}

這裏寫圖片描述
若修改爲

CTemp Double(CTemp& ts)
{
    return ts.a * 2;
}

這裏寫圖片描述

減少一次構造函數調用(tmp),一次拷貝構造函數(tmp拷貝給返回對象)調用和一次賦值拷貝函數調用
原因:返回對象直接使用爲sum預留的空間,減少了返回臨時對象的生成

參考:
http://blog.chinaunix.net/uid-10533652-id-2949402.html
http://blog.csdn.net/imyfriend/article/details/12886577

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章