c++ 臨時(shí)對(duì)象的來源
首先看下面一端代碼:
#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;
}
結(jié)果為
2-----1
可能大多數(shù)園友,認(rèn)為"int temp"是"臨時(shí)對(duì)象",但是其實(shí)不然,"int temp"僅僅是swap函數(shù)的局部變量。
臨時(shí)對(duì)象是代碼中看不到的,但是實(shí)際程序中確實(shí)存在的對(duì)象。臨時(shí)對(duì)象是可以被編譯器感知的。
為什么研究臨時(shí)對(duì)象?
主要是為了提高程序的性能以及效率,因?yàn)榕R時(shí)對(duì)象的構(gòu)造與析構(gòu)對(duì)系統(tǒng)開銷也是不小的,所以我們應(yīng)該去了解它們,知道它們?nèi)绾卧斐?,從而盡可能去避免它們。
臨時(shí)對(duì)象建立一個(gè)沒有命名的非堆對(duì)象會(huì)產(chǎn)生臨時(shí)對(duì)象。(不了解什么是堆對(duì)象和非堆對(duì)象,可以參考C++你最好不要做的這一博文,這里面有介紹。)這種未命名的對(duì)象通常在三種條件下產(chǎn)生:為了使函數(shù)成功調(diào)用而進(jìn)行隱式類型轉(zhuǎn)換時(shí)候、傳遞函數(shù)參數(shù)和函數(shù)返回對(duì)象時(shí)候。
那么首先看看為了使函數(shù)成功調(diào)用而進(jìn)行隱式類型轉(zhuǎn)換。
#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;
}
結(jié)果為:

這里調(diào)用函數(shù)countChar(const std::string& s,const char& c),那么我們看看這個(gè)函數(shù)的形參是const std::string &s,形參類型為const std::string,但是實(shí)際上傳遞的是char buffer[200]這個(gè)數(shù)組。其實(shí)這里編譯器為了使函數(shù)調(diào)用成功做了類型轉(zhuǎn)換,char *類型轉(zhuǎn)換為了std::string類型,這個(gè)轉(zhuǎn)換是通過一個(gè)賦值構(gòu)造函數(shù)進(jìn)行的,以buffer做為參數(shù)構(gòu)建一個(gè)std::string類型的臨時(shí)對(duì)象。當(dāng)constChar返回時(shí),即函數(shù)撤銷,那么這個(gè)std::string臨時(shí)對(duì)象也就釋放了。但是其實(shí)從整個(gè)程序上來說臨時(shí)對(duì)象的構(gòu)造與釋放是不必要的開銷,我們可以提高代碼的效率修改一下代碼避免無所謂的轉(zhuǎn)換。所以知道臨時(shí)對(duì)象的來源,可以對(duì)程序性能上有一個(gè)小小提升。
注意僅當(dāng)通過傳值方式傳遞對(duì)象或者傳遞常量引用參數(shù),才會(huì)發(fā)生這類型的轉(zhuǎn)換,當(dāng)傳遞非常量引用的參數(shù)對(duì)象就不會(huì)發(fā)生。因?yàn)閭鬟f非常量的引用參數(shù)的意圖就是想通過函數(shù)來改變其傳遞參數(shù)的值,但是函數(shù)其實(shí)是改變的類型轉(zhuǎn)換建立的臨時(shí)對(duì)象,所以意圖無法實(shí)現(xiàn),編譯器干脆就直接拒絕。
第二種情況是大家熟悉的函數(shù)傳遞參數(shù)的時(shí)候,會(huì)構(gòu)造對(duì)應(yīng)的臨時(shí)對(duì)象??聪旅嬉欢未a運(yùn)行的結(jié)果想必就一清二楚了。
#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;
}
結(jié)果為:

這里分析下前面兩個(gè)"h2"是通過調(diào)用構(gòu)造函數(shù)People(std::string n,int a)打印出來的,而"h3"就是通過調(diào)用復(fù)制構(gòu)造函數(shù)People(const People&)而建立臨時(shí)對(duì)象打印出來的,h1是調(diào)用默認(rèn)構(gòu)造函數(shù)People( )打印出來的。那么怎么避免臨時(shí)對(duì)象的建立呢?很簡(jiǎn)單,我們通過引用實(shí)參而達(dá)到目的
void swap(People &p1,People &p2)
第三種情景就是函數(shù)返回對(duì)象時(shí)候。這里要注意臨時(shí)對(duì)象的創(chuàng)建是通過復(fù)制構(gòu)造函數(shù)構(gòu)造出來的。
例如 const Rationanl operator+(Rationanl a,Rationanl b)該函數(shù)的返回值的臨時(shí)的,因?yàn)樗鼪]有被命名,它只是函數(shù)的返回值。每回必須為調(diào)用add構(gòu)造和釋放這個(gè)對(duì)象而付出代價(jià)。
#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做了優(yōu)化,沒有看到臨時(shí)變量。編譯器直接跳過建立r3,使用賦值符號(hào)
r3.show( );
//相當(dāng)于 (r1*r2).show( );
return 0;
}
結(jié)果為:

這里很可惜沒有看到我們想到看到的結(jié)果,結(jié)果應(yīng)該為h2,h2,h2,h3,h4,應(yīng)該是在返回值的時(shí)候有一個(gè)賦值構(gòu)造函數(shù),建立臨時(shí)變量的,后來經(jīng)筆者網(wǎng)上查找資料證實(shí)GCC做了優(yōu)化。
相關(guān)文章
C語(yǔ)言中bool和float的用法實(shí)例解析
這篇文章主要介紹了C語(yǔ)言中bool類型和float類型的相關(guān)資料,bool類型用于聲明布爾變量,只有true和false兩種值,float類型用于存儲(chǔ)單精度浮點(diǎn)數(shù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-11-11
用C語(yǔ)言的泛型實(shí)現(xiàn)交換兩個(gè)變量值
在日常編程里面經(jīng)常會(huì)遇到交換兩個(gè)變量的內(nèi)容的任務(wù),對(duì)于泛型類型而言有兩種泛型策略來實(shí)現(xiàn),下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)。2016-08-08
C++線程池的簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了C++線程池的簡(jiǎn)單實(shí)現(xiàn)方法,包括了線程操作函數(shù)及相關(guān)屬性的用法,需要的朋友可以參考下2014-09-09
c++ 網(wǎng)絡(luò)庫(kù)asio的優(yōu)勢(shì)
這篇文章主要介紹了c++ 網(wǎng)絡(luò)庫(kù)asio的優(yōu)勢(shì),幫助大家更好的利用c++開發(fā)服務(wù)端程序,感興趣的朋友可以了解下2020-10-10
C語(yǔ)言實(shí)現(xiàn)掃雷游戲及其優(yōu)化
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲及其優(yōu)化,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08

