当以一个函数内的临时变量对象作为另一个函数的形参的时候,原函数内的临时对象即 rvalue,就会成为此函数内的 lvalue。
这样会重新导致效率低下,因为造成了大量复制操作。
<utility>头文件提供了 std:move()函数。此函数返回作为 rvalue 传递给的任何实参。
观察下面程序的输出:
class CText { private: char *pText; public: void showIt()const { cout << pText << endl; } CText(const char* pStr = "No text") { cout << "CText constructor called" << endl; size_t len{ strlen(pStr) + 1 }; pText = new char[len]; strcpy_s(pText, len, pStr); } CText(const CText & txt) { cout << "CText copy constructor called" << endl; size_t len{ strlen(txt.pText) + 1 }; pText = new char[len]; strcpy_s(pText, len, txt.pText); } CText(CText && txt) { cout << "CText move constructor called" << endl; pText = txt.pText; txt.pText = nullptr; } ~CText() { cout << "CText destructor called" << endl; delete[]pText; } CText & operator=(const CText & txt) { cout << "CText assignment operator function called" << endl; if (this != &txt) { delete[]pText; size_t length{ strlen(txt.pText) + 1 }; pText = new char[length]; strcpy_s(pText, length, txt.pText); } return *this; } CText & operator=(CText && txt) { cout << "CText move assignment operator function called" << endl; delete[]pText; pText = txt.pText; txt.pText = nullptr; return *this; } CText operator+(const CText & txt)const { cout << "CText add operator function called" << endl; size_t length{ strlen(pText) + strlen(txt.pText) + 1 }; CText aText; aText.pText = new char[length]; strcpy_s(aText.pText, length, pText); strcat_s(aText.pText, length, txt.pText); return aText; } };
CText 实现了移动语义的复制构造和赋值运算符函数,并且CText的对象作为CMessage类的成员。
class CMessage { private: CText m_Text; public: void showIt()const { m_Text.showIt(); } CMessage operator+(const CMessage & aMess) const { cout << "CMessage add operator function called" << endl; CMessage message; message.m_Text = m_Text + aMess.m_Text; return message; } CMessage & operator=(const CMessage & aMess) { cout << "CMessage assignment operator function called" << endl; if (this != &aMess) { m_Text = aMess.m_Text; } return *this; } CMessage & operator=(CMessage && aMess) { cout << "CMessage move assignment operator function called" << endl; m_Text = aMess.m_Text; return *this; } CMessage(const char * str = "Default message")//:m_Text{ str }//m_Text { CText(str) } { cout << "CMessage constructor called----" << endl; m_Text = CText(str); } CMessage(const CMessage & amess) { cout << "cmessage copy constructor called" << endl; m_Text = amess.m_Text; } CMessage(const CMessage && amess) { cout << "cmessage move constructor called" << endl; m_Text = amess.m_Text; } }; int main() { CMessage motto1{"The devi1 takes care of his own. "}; cout << "----------------------------------------" << endl; CMessage motto2{"if yuo sup with the devil use a long spoon. "}; cout << "----------------------------------------" << endl; CMessage motto3{motto1+motto2}; cout << "----------------------------------------" << endl; motto3.showIt(); }
注意:CMessage 的构造函数,用初始化列表和在构造函数中初始化的差别。
当用初始化列表的输出如下:
:m_Text { CText(str) }
CText constructor called
CMessage constructor called
----------------------------------------
CText constructor called
CMessage constructor called
----------------------------------------
CMessage add operator function called
CText constructor called
CMessage constructor called
CText add operator function called
CText constructor called
CText move constructor called
CText destructor called
CText move assignment operator function called
CText destructor called
CText constructor called
cmessage copy constructor called
CText assignment operator function called
CText destructor called
----------------------------------------
The devi1 takes care of his own.
if yuo sup with the devil use a long spoon.
CText destructor called
CText destructor called
CText destructor called
用思维把运行过程走一遍,会发现红色部分出现问题(rvalue 被函数当成 lvalue 使用)。
也许你会疑惑临时变量的生成等操作,并没有输出,因为它们是编译器暗地做的工作。就像按值传递一样,我们也一无所知。
方法:
若想要避免我们所看到的红色标记问题,使用移动语义就可以 std:move() 。
CMessage(const CMessage && amess)
{
cout << "cmessage move constructor called" << endl;
m_Text = std::move(amess.m_Text);
}
CMessage & operator=(CMessage && aMess)
{
cout << "CMessage move assignment operator function called" << endl;
// m_Text = std::move(aMess.m_Text);
m_Text = static_cast<CText &&>(aMess.m_Text); //和 std:move() 功能一样,属于强制转换
return *this;
}
问题再描述:
如果我们已经按如上方式做了努力,而 CMessage & operator=( const CMessage && aMess),使用了 const ,使用移动语义也是没了效果。
这属于 const 类型函数,调用 const 函数问题。