1. 程式人生 > >C++:臨時量&臨時物件

C++:臨時量&臨時物件

臨時量
      ·   內建型別生成的臨時量是常量(臨時量,暫存器帶出來)。
      ·   自定義型別生成的臨時量是變數 ,在記憶體中。
      ·   隱式生成生成的臨時量是常量 ,顯式生成生成的臨時量是變數 。

臨時物件
         臨時物件是系統臨時分配的物件,在沒主動宣告所需物件而又使用其功能時產生的。

何時產生臨時物件

  1)以值的方式給函式傳參;


#include<iostream>

class Test
{
public:

	Test(int a, int b)
	{
		std::cout << this << " :Test::Test(int,int)" << std::endl;
		ma = a;
		mb = b;
	}

	Test(int a)
	{
		std::cout << this << " :Test::Test(int)" << std::endl;
		ma = a;
		mb = 0;
	}

	Test()
	{
		std::cout << this << " :Test::Test()" << std::endl;
		ma = mb = 0;
	}

	Test(const Test& rhs)
	{
		std::cout << this << " :Test::Test(const Test&)" << std::endl;
		ma = rhs.ma;
		mb = rhs.mb;
	}

	Test& operator=(const Test& rhs)
	{
		std::cout << this << " :Test::operator=(const Test&)" << std::endl;
		if (this != &rhs)
		{
			ma = rhs.ma;
			mb = rhs.mb;
		}
		return *this;
	}

	~Test()
	{
		std::cout << this << " :Test::~Test()" << std::endl;
	}

	
private:
	int ma;
	int mb;
};

void getObject(Test lhs)
{

}

int main()
{
	Test test1(10, 20);//呼叫了帶有兩個引數的建構函式
	getObject(test1);//按值傳遞,已存在的物件生成一個相同型別的新(臨時)物件,呼叫拷貝建構函式創造了一個副本。
	return 0;
}

列印結果

  

針對這種情況,將形參傳入物件引用,因為引用只是物件的一個別名,不會產生臨時物件,程式碼修改如下:

   

2)型別轉換;


#include<iostream>

class Test
{
public:

	Test(int a, int b)
	{
		std::cout << this << " :Test::Test(int,int)" << std::endl;
		ma = a;
		mb = b;
	}

	Test(int a)
	{
		std::cout << this << " :Test::Test(int)" << std::endl;
		ma = a;
		mb = 0;
	}

	Test()
	{
		std::cout << this << " :Test::Test()" << std::endl;
		ma = mb = 0;
	}

	Test(const Test& rhs)
	{
		std::cout << this << " :Test::Test(const Test&)" << std::endl;
		ma = rhs.ma;
		mb = rhs.mb;
	}

	Test& operator=(const Test& rhs)
	{
		std::cout << this << " :Test::operator=(const Test&)" << std::endl;
		if (this != &rhs)
		{
			ma = rhs.ma;
			mb = rhs.mb;
		}
		return *this;
	}

	~Test()
	{
		std::cout << this << " :Test::~Test()" << std::endl;
	}

private:
	int ma;
	int mb;
};

int main()
{
	Test test1;//呼叫預設建構函式
	test1=10;//表示式左右型別不匹配,右邊,已存在的物件先生成一個相同型別的新(臨時)物件,呼叫帶有一個引數的建構函式,
                 //然後這個已存在的(臨時)物件賦值給相同型別的已存在的物件	
	return 0;
}

列印結果

針對這種情況,對main函式中的程式碼稍作修改,將不會產生臨時物件,程式碼修改如下:

這其實是一種優化: 即臨時物件生成的目的是為了生成新物件,則以生成臨時物件的方式來生成新物件。

原因:當我們定義Test test1時,在main的棧中為test1物件建立了一個預留的空間。而我們用10呼叫構造時,此時的構造是在為test1預留的空間中進行的,因此減少了一次臨時物件的建立。

    

3)函式需要返回一個物件時;

#include<iostream>

class Test
{
public:

	Test(int a, int b)
	{
		std::cout << this << " :Test::Test(int,int)" << std::endl;
		ma = a;
		mb = b;
	}

	Test(int a)
	{
		std::cout << this << " :Test::Test(int)" << std::endl;
		ma = a;
		mb = 0;
	}

	Test()
	{
		std::cout << this << " :Test::Test()" << std::endl;
		ma = mb = 0;
	}

	Test(const Test& rhs)
	{
		std::cout << this << " :Test::Test(const Test&)" << std::endl;
		ma = rhs.ma;
		mb = rhs.mb;
	}

	Test& operator=(const Test& rhs)
	{
		std::cout << this << " :Test::operator=(const Test&)" << std::endl;
		if (this != &rhs)
		{
			ma = rhs.ma;
			mb = rhs.mb;
		}
		return *this;
	}

	~Test()
	{
		std::cout << this << " :Test::~Test()" << std::endl;
	}

	int getValue()
	{
		return ma;
	}
private:
	int ma;
	int mb;
};

Test getObject(Test &lhs)
{
	Test tmp;//呼叫預設建構函式
	tmp = lhs.getValue();//表示式右邊,呼叫帶有一個引數的建構函式,生成臨時物件,
	//然後已存在的物件賦值給相同型別的已存在的函式,呼叫賦值運算子過載函式,
	return tmp;//已存在的物件生成一個相同型別的新(臨時)物件,呼叫拷貝建構函式。
}

int main()
{
	Test test1(10,20);//呼叫帶有兩個引數的建構函式
	getObject(test1);                   
	return 0;
}

列印結果

針對這種情況,直接返回物件,發現減少了一次建構函式呼叫,一次拷貝建構函式呼叫和一次賦值拷貝函式呼叫。

    

return lhs.getValue(); 與Test tmp=lhs.getValue();等價

先呼叫帶有一個引數的建構函式,生成臨時物件,這個臨時物件生成的目的是為了生成新物件,故有優化。