欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析C++中臨時對象的產(chǎn)生情況

 更新時間:2023年06月19日 11:01:54   作者:Allen.Su  
臨時對象的產(chǎn)生和銷毀都是有成本的,都會影響程序的執(zhí)行性能和效率,所以如果能了解臨時對象產(chǎn)生的原因,就可以提升程序的性能和效率,下面小編就來和大家聊聊臨時對象產(chǎn)生的幾種情況吧

有些臨時對象是系統(tǒng)自己產(chǎn)生的,又有一些臨時對象卻是因為代碼的書寫問題而產(chǎn)生的,因為臨時對象會額外消耗系統(tǒng)資源,所以編寫代碼的原則就是產(chǎn)生的臨時對象越少越好。臨時對象一般都是在棧上,所以一般都不會手動去釋放。

為什么要了解臨時對象?因為臨時對象的產(chǎn)生和銷毀都是有成本的,都會影響程序的執(zhí)行性能和效率,所以如果能有效地減少臨時對象的產(chǎn)生,那么無疑意味著程序性能和效率的提升。

一、產(chǎn)生臨時對象的情況

1.1 以值的方式給函數(shù)傳遞參數(shù) - 如何優(yōu)化呢

先看如下案例:

class CTempValue
{
public:
    int val1;
    int val2;
public:
    //構(gòu)造函數(shù)
    CTempValue(int v1 = 0, int v2 = 0)
    {
        cout << "調(diào)用構(gòu)造函數(shù)" << endl;
        val1 = v1;
        val2 = v2;
        cout << "val1 = " << val1 << endl;
        cout << "val2 = " << val2 << endl;
    }
    ~CTempValue()
    {
        cout << "調(diào)用了析構(gòu)函數(shù)" << endl;
    }
    //拷貝構(gòu)造函數(shù)
    CTempValue(const CTempValue& t)
    {
        cout << "調(diào)用拷貝構(gòu)造函數(shù)" << endl;
        val1 = t.val1;
        val2 = t.val2;
        cout << "val1 = " << val1 << endl;
        cout << "val2 = " << val2 << endl;
    }
    int Add(CTempValue tobj)
    {
        int tmp = tobj.val1 + tobj.val2;
        tobj.val1 = 1000;   //這里的修改對外界沒有影響
        return tmp;
    }
};
???????int main()
{
    CTempValue tm(10, 20);  //調(diào)用構(gòu)造函數(shù)
    int Sum = tm.Add(tm);   // 這會調(diào)用拷貝構(gòu)造函數(shù)的執(zhí)行
    cout << "Sum = " << Sum << endl;  //Sum = 30
    cout << "tm.val1 = " << tm.val1 << endl; //tm.val1 = 10
    return 0;
}

運行結(jié)果如下:

調(diào)用構(gòu)造函數(shù)
調(diào)用拷貝構(gòu)造函數(shù)
調(diào)用了析構(gòu)函數(shù)
Sum = 30
tm.val1 = 10
調(diào)用了析構(gòu)函數(shù)

請注意,結(jié)果中調(diào)用了拷貝構(gòu)造函數(shù),為什么調(diào)用CTempValue類的拷貝構(gòu)造函數(shù)呢?

這是因為調(diào)用Add成員函數(shù)時把對象tm傳遞給了Add成員函數(shù),此時,系統(tǒng)會調(diào)用拷貝構(gòu)造函數(shù)創(chuàng)建一個副本tobj(成員函數(shù)Add的形參),用于在函數(shù)體Add內(nèi)使用,因為tm對象的vall值(tm對象的vall值仍舊為10)。

形參tobj是一個局部對象(局部變量),從程序功能的角度來講,函數(shù)體內(nèi)需要臨時使用它一下,來完成一個程序上的一個功能,它確實是一個局部變量,只能在Add函數(shù)體里使用。所以嚴(yán)格意義來講,它又不能稱為一個真正意義的臨時對象,因為真正的臨時對象往往指的是真實存在,但又感覺不到的對象(至少從代碼上不能直接看到的對象)。

但是,對于目前確實生成了tobj對象,并且調(diào)用了類的拷貝構(gòu)造函數(shù),有了復(fù)制的動作,就會影響程序的執(zhí)行效率。

那如何優(yōu)化呢?

我們可以使用引用:

int Add(CTempValue& tobj){}

1.2 類型轉(zhuǎn)換生成的臨時對象 - 如何優(yōu)化呢

1.2.1 類型轉(zhuǎn)換生成的臨時對象

接下來,我們看下真正意義的臨時對象,因為這個臨時對象確實存在,但是從程序代碼的角度不能直接看到它。

CTempValue sum;
sum = 1000;

執(zhí)行一下,程序結(jié)果如下:

調(diào)用構(gòu)造函數(shù)
val1 = 0
val2 = 0
調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)
調(diào)用了析構(gòu)函數(shù)

在執(zhí)行sum = 1000;系統(tǒng)調(diào)用了一次CTempValue類的構(gòu)造函數(shù)和析構(gòu)函數(shù),這說明系統(tǒng)肯定產(chǎn)生了一個對象,但這個對象在哪里,通過代碼完全看不到,所以這個對象是一個真正的臨時對象。

那么,產(chǎn)生這個臨時對象的原因是什么呢?

是因為把1000賦給sum,而sum本身是一個CTempValue類型的對象,1000是一個數(shù)字,那怎么把數(shù)字能轉(zhuǎn)化成CTempValue類型的對象呢?所以編譯器這里幫助我們以1000為參數(shù)調(diào)用了CTempValue的構(gòu)造函數(shù)創(chuàng)建了一個臨時對象,因為CTempValue構(gòu)造函數(shù)的兩個參數(shù)都有默認(rèn)值,所以這里的數(shù)字1000就頂替了第一個參數(shù),而第二個參數(shù)系統(tǒng)就用了默認(rèn)值,所以從1000是可以成功創(chuàng)建出CTempValue對象的。

為了進(jìn)一步觀察,增加拷貝賦值運算符的代碼:

CTempValue& operator=(const CTempValue& tmpv)
{
    cout << "調(diào)用了拷貝賦值運算符" << endl;
    val1 = tmpv.val1;
    val2 = tmpv.val2;
    cout << "val1 = " << val1 << endl;
    cout << "val2 = " << val2 << endl;
    return *this;
}

執(zhí)行程序,看下結(jié)果:

調(diào)用構(gòu)造函數(shù)
val1 = 0
val2 = 0
調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了拷貝賦值運算符
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)
調(diào)用了析構(gòu)函數(shù)

總結(jié)sum = 1000;這行代碼系統(tǒng)做了哪些事:

用1000這個數(shù)字創(chuàng)建了一個類型為CTempValue的臨時對象;調(diào)用拷貝賦值運算符把這個臨時對象里面的各個成員值賦給了sum對象;銷毀這個剛剛創(chuàng)建的CTempValue臨時對象。

那如何優(yōu)化呢?

可以把main主函數(shù)中剛剛寫的兩行代碼優(yōu)化成下面一行:

CTempValue sum = 1000; //" = " 在這里不是賦值運算符,而是定義初始化的概念

運行結(jié)果如下:

調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)

可以看到,系統(tǒng)沒有生成臨時對象,所以系統(tǒng)少調(diào)用了一次構(gòu)造函數(shù),少調(diào)用了一次拷貝賦值運算符、少調(diào)用了一次析構(gòu)函數(shù)。

1.2.2 隱式類型轉(zhuǎn)換以保證函數(shù)調(diào)用成功

int calc(const string& strsource, char ch)
{
    const char * p = strsource.c_str();
    int icount = 0;
    //......具體的統(tǒng)計代碼
    return icount;
}
//在main主函數(shù)的代碼如下:
int main()
{
    char mystr[100] = "I love China, oh, yeah!";
    int result = calc(mystr, 'o');
    return 0;
}

一個是char數(shù)組,一個是const string&,但是這個函數(shù)就能調(diào)用成功,為什么呢?

當(dāng)然是編譯器幫助我們做了一些事情,解決類型不匹配,那是如何做的呢?

那就是編譯器產(chǎn)生了一個類型sring的臨時對象,這個臨時對象的構(gòu)造方式就是用mystr作為參數(shù),調(diào)用了string的構(gòu)造函數(shù),這樣形參strsoutce就綁定到這個string臨時對象上了。當(dāng)calc函數(shù)返回的時候,這個臨時對象會被自動銷毀。

C++只會為const string&(const引用)產(chǎn)生臨時對象,不會為string&(非const)產(chǎn)生臨時對象。

1.3 函數(shù)返回值的時候 - 如何優(yōu)化呢

我們在main主函數(shù)上面加一個普通的全局函數(shù):

CTempValue Double(CTempValue& ts)
{
    CTempValue tmpm;    //這里會消耗一次構(gòu)造函數(shù)和一次析構(gòu)函數(shù)的調(diào)用
    tmpm.val1 = ts.val1 * 2;
    tmpm.val2 = ts.val2 * 2;
    return tmpm; //這里會調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),這表示生成了一個臨時對象
}
int main()
{
    CTempValue ts1(10, 20);
    CTempValue ts2 = Double(ts1);  //其實臨時對象接管的就是右值
    CTempValue&& ts2 = Double(ts1);  
}

臨時對象就是一種右值

那如何優(yōu)化呢?

CTempValue Double(CTempValue& ts)
{
    return CTempValue(ts.val1 * 2, ts.val2 * 2); 
}

通過如上的優(yōu)化系統(tǒng)會調(diào)用一次拷貝構(gòu)造函數(shù),一次析構(gòu)函數(shù)。

二、小結(jié)

(1)寫代碼的時候,減少臨時變量的產(chǎn)生。

(2)鍛煉眼神,能夠盡量看出哪些地方可能會產(chǎn)生臨時對象,尤其是一個函數(shù)只要返回一個對象,一般機會產(chǎn)生臨時對象。

到此這篇關(guān)于解析C++中臨時對象的產(chǎn)生情況的文章就介紹到這了,更多相關(guān)C++臨時對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論