c++ 臨時對象的來源

來源:互聯網
上載者:User

首先看下面一端代碼:

複製代碼 代碼如下: #include <iostream>
void swap( int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}

int main(int argc,char** argv)
{
int a=1,b=2;
swap(a,b);
std::cout<<a<<"-----"<<b<<std::endl;
return 0;
}

結果為
2-----1
可能大多數園友,認為"int temp"是"臨時對象",但是其實不然,"int temp"僅僅是swap函數的局部變數。

臨時對象是代碼中看不到的,但是實際程式中確實存在的對象。臨時對象是可以被編譯器感知的。

為什麼研究臨時對象?
主要是為了提高程式的效能以及效率,因為臨時對象的構造與析構對系統開銷也是不小的,所以我們應該去瞭解它們,知道它們如何造成,從而儘可能去避免它們。

臨時對象建立一個沒有命名的非堆對象會產生臨時對象。(不瞭解什麼是堆對象和非堆對象,可以參考C++你最好不要做的這一博文,這裡面有介紹。)這種未命名的對象通常在三種條件下產生:為了使函數成功調用而進行隱式類型轉換時候、傳遞函數參數和函數返回對象時候。

那麼首先看看為了使函數成功調用而進行隱式類型轉換。

複製代碼 代碼如下: #include <iostream>
int countChar(const std::string & s,const char c)
{
int count=0;
for(int i=0;i<s.length( );i++)
{
if(*(s.c_str( )+i) == c)
{
count++;
}
}
return count;
}

int main(int argc,char** argv)
{
char buffer[200];
char c;
std::cout<<"please input the string:";
std::cin>>buffer;
std::cout<<"please input the char which you want to chount:";
std::cin>>c;
int count=countChar(buffer,c);
std::count<<"the count is:"<<count<<std::endl;
return 0;
}

結果為:

這裡調用函數countChar(const std::string& s,const char& c),那麼我們看看這個函數的形參是const std::string &s,形參類型為const std::string,但是實際上傳遞的是char buffer[200]這個數組。其實這裡編譯器為了使函數調用成功做了類型轉換,char *類型轉換為了std::string類型,這個轉換是通過一個賦值建構函式進行的,以buffer做為參數構建一個std::string類型的臨時對象。當constChar返回時,即函數撤銷,那麼這個std::string臨時對象也就釋放了。但是其實從整個程式上來說臨時對象的構造與釋放是不必要的開銷,我們可以提高代碼的效率修改一下代碼避免無所謂的轉換。所以知道臨時對象的來源,可以對程式效能上有一個小小提升。

注意僅當通過傳值方式傳遞對象或者傳遞常量引用參數,才會發生這類型的轉換,當傳遞非常量引用的參數對象就不會發生。因為傳遞非常量的引用參數的意圖就是想通過函數來改變其傳遞參數的值,但是函數其實是改變的類型轉換建立的臨時對象,所以意圖無法實現,編譯器乾脆就直接拒絕。

第二種情況是大家熟悉的函數傳遞參數的時候,會構造對應的臨時對象。看下面一段代碼啟動並執行結果想必就一清二楚了。

複製代碼 代碼如下: #include<iostream>
class People
{
public:
People(std::string n,int a)
:name(n),age(a)
{
std::count<<"h2"<<std::endl;
}
People( )
{
std::count<<"h1"<<std::endl;
}
People(const People& P)
{
name=p.name;
age=p.age;
std::cout<<"h3"<<std::endl;
}
std::string name;
int age;
};

void swap(People p1,People p2)
{
People temp;
temp.age=p1.age;
temp.name=p1.name;
p1.age=p2.age;
p1.name=p2.name;
p2.age=temp.age;
p2.name=temp.name;
}

int main(int argc, char ** argv)
{
People p1("tom",18),p2("sam",19);
swap(p1,p2);
return 0;
}

結果為:

這裡分析下前面兩個"h2"是通過調用建構函式People(std::string n,int a)列印出來的,而"h3"就是通過調用複製建構函式People(const People&)而建立臨時對象列印出來的,h1是調用預設建構函式People( )列印出來的。那麼怎麼避免臨時對象的建立呢?很簡單,我們通過引用實參而達到目的

void swap(People &p1,People &p2)
第三種情景就是函數返回對象時候。這裡要注意臨時對象的建立是通過複製建構函式構造出來的。

例如 const Rationanl operator+(Rationanl a,Rationanl b)該函數的傳回值的臨時的,因為它沒有被命名,它只是函數的傳回值。每回必須為調用add構造和釋放這個對象而付出代價。

複製代碼 代碼如下: #include <iostream>
class Rationanl
{
public:
Rationanl(int e,int d)
:_elemem(e),_denom(d)
{
std::cout<<"h2"<<std::endl;
}
void show( ) const;
int elemem() const {return _elemem;}
int denom() const {return _denom;}
void setElemon(int e){_elemon=e;}
void setDenom(int d) {_denom=d;}
Rationanl(const Rationanl &r);
Rationanl & operator=(const Rationanl &r);
private:
int _elemem;
int _denom;
};
Rationanl::Rationanl(const Rationanl &r)
{
setElemon(r.elemon( ));
setDenom(r.denom( ) );
std::cout<<"h3"<<std::endl;
}
Rationanl & Rationanl::operator=(const Rationanl &r)
{
setElemon(r.elemon( ));
setDenom(r.denom( ) );
std::cout<<"h4"<<std::endl;
return *this;
}

void Rationanl::show( )
{
std::cout<<_elemen<<"/"<<_denom<<std::endl;
}
const Rationanl operator*(const Rationanl lhs,const Rationanl rhs)
{
return Rational result(lhs.elemen*rhs.elemen,rhs.denom*rhs.denom);
}

int main(int argc,char **argv)
{
Rationanl r1(1,2),r2(1,3)
Rationanl r3=r1*r2; //GCC做了最佳化,沒有看到臨時變數。編譯器直接跳過建立r3,使用賦值符號
r3.show( );
//相當於 (r1*r2).show( );
return 0;
}

結果為:

這裡很可惜沒有看到我們想到看到的結果,結果應該為h2,h2,h2,h3,h4,應該是在傳回值的時候有一個賦值建構函式,建立臨時變數的,後來經筆者網上尋找資料證實GCC做了最佳化。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.