1. 程式人生 > >第二十三課:神祕的臨時物件----------狄泰軟體學院

第二十三課:神祕的臨時物件----------狄泰軟體學院

一、直接呼叫建構函式

#include<iostream>
using namespace std;
class Test
{
private:
    int mi;
public:
    Test(int v)
    {
        mi = v;
    }
    Test()
    {
        Test(0);//直接呼叫建構函式,看起來合情合理,但卻是產生了一個臨時物件,這句之後馬上被析構,等價於這行根本沒有
    }
    void print()
    {
        cout<<"mi = "<<mi<<endl;//最後列印mi的值為隨機值  
} }; int main() { Test t; t.print(); cin.get(); return 0; }

本來的意圖:
在Test()中以0作為引數呼叫Test(int i),想將成員變數mi的初始值設定為0
但最終mi的值卻是隨機值

原因:
1.直接呼叫建構函式將產生一個臨時物件
2.臨時物件的宣告週期只有一條語句的時間
3.臨時物件的作用域只在一條語句
4.臨時物件是c++中值得警惕的灰色地帶

解決方案:定義一個私有的初始化函式

#include<iostream>
using namespace std
; class Test { private: int mi; void init(int v) { mi = v; } public: Test(int v) { mi = v; } Test() { init(2); } void print() { cout<<"mi = "<<mi<<endl;//最後列印mi的值為2 } }; int main() { Test t; t.print(); cin
.get(); return 0; }

二、產生一個臨時物件後馬上呼叫print函式

#include<iostream>
using namespace std;
class Test
{
private:
    int mi;
    void init(int i)
    {
        mi = i;
    }
public:
    Test(int v)
    {
        cout<<"Test(int v) begin"<<endl;
        mi = v;
        cout<<"Test(int v) end"<<endl;
    }
    Test()
    {
        cout<<"Test() begin"<<endl;
        init(1);
        cout<<"Test() end"<<endl;
    }
    void print()
    {
        cout<<"mi = "<<mi<<endl;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }

};
int main()
{
    cout<<"main() begin"<<endl;
    Test().print();
    Test(2).print();
    cout<<"main() endl"<<endl;  
    return 0;
}
列印結果:
main() begin
Test() begin
Test() end
mi = 1//先列印mi的值才呼叫解構函式
~Test()
Test(int v) begin
Test(int v) end
mi = 2
~Test()
main() endl
說明在那行程式完之後才呼叫解構函式

現代編譯器在不影響最終執行結果的情況下極力減少臨時物件的產生

#include<iostream>
using namespace std;
class Test
{
private:
    int mi;
public:
    Test(int v)
    {
        cout<<"Test(int v)"<<endl;
        mi = v;
    }
    Test(const Test& obj)
    {
        cout<<"Test(const Test& obj)"<<endl;
        mi = obj.mi;
    }
    void print()
    {
        cout<<"mi = "<<mi<<endl;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }

};
int main()
{
    Test t = Test(10);;//1.生產一個臨時物件 2.用臨時物件初始化t  ===》呼叫拷貝建構函式(但是實際上並沒有拷貝建構函式的跡象)
                      //少呼叫一次拷貝建構函式,最終等價於t=10;這裡也就解決了之前Ta[3] = {Test(),Test(1),Test(2)};合法的問題
    t.print();
        cout<<"main() end"<<endl;
    return 0;
}
列印結果:
Test(int v)
mi = 10
main() end
~Test()//解構函式被最後列印,且只調用了一次建構函式說明只是t在建立時呼叫了,而臨時物件相當於沒有

小結:

1.直接呼叫建構函式將產生一個臨時物件
2.臨時物件是效能的瓶頸,也是bug的重要來源之一
3.現代c++編譯器會極力避免臨時物件
4.程式設計中也要人為避開臨時物件