函數返回語句與copy (move) constructor, copy (move) assignment operator的關係

考察下面的函數:

// This program is designed to test the relationship between the 
// return statements and the copy (move) constructors.
#include <iostream>
#include <vector>
#include <string>

using namespace std;

class IntCell
{
public:
	IntCell(int num = 0) :m_iNum(num)
	{
		cout << "\nInt-parameter constructor called.\n";
	}
	// Copy constructor
	IntCell(const IntCell & rhs) :m_iNum(rhs.m_iNum)
	{
		cout << "\nThe copy constructor called.\n";
	}
	// Move constructor
	IntCell(IntCell && rhs) :m_iNum(std::move(rhs.m_iNum))
	{
		cout << "\nThe move constructor called.\n";
	}
	// Copy assignment operator
	IntCell& operator=(const IntCell& rhs)
	{
		cout << "\nThe copy assignment operator called.\n";
		if (this != &rhs)
			m_iNum = rhs.m_iNum;

		return *this;
	}
	// Move assignment operator
	IntCell& operator=(IntCell&& rhs)
	{
		cout << "\nThe move assignment operator called.\n";
		std::swap(m_iNum, rhs.m_iNum);
		return *this;
	}

	IntCell operator+(const IntCell & rhs)
	{
		IntCell sum;
		sum.m_iNum = m_iNum + rhs.m_iNum;
		return sum;
	}
private:
	int m_iNum;
};

IntCell func1(int n)
{
	IntCell temp{ n };
	return temp;
}

IntCell func2(int n)
{
	return IntCell(n);
}

IntCell& firstItem(vector<IntCell> & IntCellVec)
{
	cout << "\nNon-const version of firstItem called.\n";
	return IntCellVec[0];
}

const IntCell& firstItem(const vector<IntCell> & IntCellVec)
{
	cout << "\nConst version of firstItem called.\n";
	return IntCellVec[0];
}

void separation( )
{
	cout << "\n------------------------------------------------------\n";
}

int main( )
{
	int num = 12;
	cout << "\nThe functions invoked by\nfunc1(num);\n";
	func1(num);
	separation( );
	cout << "\nThe functions invoked by\nfunc2(num);\n";
	func2(num);
	separation();
	cout << "\nThe functions invoked by\nIntCell myIntCell (func1(num));\n";
	IntCell myIntCell (func1(num));
	separation();
	cout << "\nThe functions invoked by\nIntCell yourIntCell(myIntCell);\n";
	IntCell yourIntCell(myIntCell);
	separation();
	cout << "\nThe functions invoked by\nIntCell hisIntCell(std::move(myIntCell));\n";
	IntCell hisIntcell(std::move(myIntCell));
	separation( );

	vector<IntCell> myIntCellVec;
	myIntCellVec.push_back(IntCell(1));
	myIntCellVec.push_back(IntCell(2));
	myIntCellVec.push_back(IntCell(3));

	IntCell addent(2);
	IntCell result;
	separation();
	cout << "\nThe functions invoked by\n" << "IntCell& rsl = firstItem(myIntCellVec);\n";
	IntCell& rsl = firstItem(myIntCellVec);
	separation();
	cout << "\nThe functions invoked by\n" << "result = firstItem(myIntCellVec);\n";
	result = firstItem(myIntCellVec);
	separation();
	cout << "\nThe functions invoked by\n" << "result = firstItem(myIntCellVec) + addent;\n";
	
	result = firstItem(myIntCellVec) + addent;
	system("pause");
}

上述代碼在Visual Studio2013環境下的運行結果是:

The functions invoked by
func1(num);
 
Int-parameter constructor called.
 
The move constructor called.
 
------------------------------------------------------
 
The functions invoked by
func2(num);
 
Int-parameter constructor called.
 
------------------------------------------------------
 
The functions invoked by
IntCell myIntCell (func1(num));
 
Int-parameter constructor called.
 
The move constructor called.
 
------------------------------------------------------
 
The functions invoked by
IntCell yourIntCell(myIntCell);
 
The copy constructor called.
 
------------------------------------------------------
 
The functions invoked by
IntCell hisIntCell(std::move(myIntCell));
 
The move constructor called.
 
------------------------------------------------------
 
……
 
------------------------------------------------------
 
The functions invoked by
IntCell& rsl = firstItem(myIntCellVec);
 
Non-const version of firstItem called.
 
------------------------------------------------------
 
The functions invoked by
result = firstItem(myIntCellVec);
 
Non-const version of firstItem called.
 
The copy assignment operator called.
 
------------------------------------------------------
 
The functions invoked by
result = firstItem(myIntCellVec) + addent;
 
Non-const version of firstItem called.
 
Int-parameter constructor called.
 
The move constructor called.
 
The move assignment operator called.

下面我們來逐一分析之。

一,

The functions invoked by
func1(num);
 
Int-parameter constructor called.
 
The move constructor called.
 
------------------------------------------------------

之所以會調用move constructor,是因爲……你記住它就行了。有的編譯器不會調用。不過在寫代碼的時候不要做出過於樂觀的估計。

二,

The functions invoked by
func2(num);
 
Int-parameter constructor called.
 
------------------------------------------------------

之所以這次沒有調用move constructor,是因爲編譯器進行了優化。同樣,寫代碼的時候不要做出過於樂觀的估計。

三,

The functions invoked by
IntCell myIntCell (func1(num));
 
Int-parameter constructor called.
 
The move constructor called.
 
------------------------------------------------------

這個沒啥可說的。

四,

The functions invoked by
IntCell yourIntCell(myIntCell);
 
The copy constructor called.
 
------------------------------------------------------

這個也沒啥可說的。

五,

The functions invoked by
IntCell hisIntCell(std::move(myIntCell));
 
The move constructor called.
 
------------------------------------------------------

同樣,沒啥可說的。

 

六,

------------------------------------------------------
 
The functions invoked by
IntCell& rsl = firstItem(myIntCellVec);
 
Non-const version of firstItem called.

這個語句調用的函數出人意料地少。這是因爲參數的傳遞及返回都是通過reference來實現的。

七,

------------------------------------------------------
 
The functions invoked by
result = firstItem(myIntCellVec);
 
Non-const version of firstItem called.
 
The copy assignment operator called.

雖然firstItem函數返回的是引用,但是如果沒有合理利用這一點的話,還是會調用copy assignment operator的。

八,

------------------------------------------------------
 
The functions invoked by
result = firstItem(myIntCellVec) + addent;
 
Non-const version of firstItem called.
 
Int-parameter constructor called.
 
The move constructor called.
 
The move assignment operator called.
這裏調用了Int-parameter constructor是因爲 operator+裏構造了sum對象,後面的moveconstructor被調用是因爲operator+是按值返回的。最後的move assignment operator被調用是因爲operator+按值返回的對象是右值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章