考察下面的函數:
// 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+按值返回的對象是右值。