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