8.5.3 命名的对象是lvalue(1)
当调用CMessage类中具有rvalue引用形参的赋值运算符函数时,我们肯定知道实参(即右操作数)是一个rvalue,因此,它是一个临时对象,我们可以偷用它的内存。但是,在此运算符函数的函数体内,形参aMess是一个lvalue。这是因为任何表达式,如果是一个命名的变量,则它是一个lvalue。这可能会重新导致效率低下,我们会通过下面这个示例来演示说明这一点,该示例使用CMessage类的修改版本。
- class CMessage
- {
- private:
- CText text; // Object text string
- public:
- // Function to display a message
- void ShowIt() const
- {
- text.ShowIt();
- }
- // Overloaded addition operator
- CMessage operator+(const CMessage& aMess) const
- {
- cout << "CMessage add operator function called." << endl;
- CMessage message;
- message.text = text + aMess.text;
- return message;
- }
- // Copy assignment operator for CMessage objects
- CMessage& operator=(const CMessage& aMess)
- {
- cout << "CMessage copy assignment operator function called." << endl;
- if(this == &aMess) // Check addresses, if equal
- {
- text = aMess.text;
- }
- return *this; // Return a reference to 1st operand
- }
- // Move assignment operator for CMessage objects
- CMessage& operator=(CMessage&& aMess)
- {
- cout << "CMessage move assignment operator function called." << endl;
- text = aMess.text;
- return *this; // Return a reference to 1st operand
- }
- // Constructor definition
- CMessage(const char* str = "Default message")
- {
- cout << "CMessage constructor called." << endl;
- text = CText(str);
- }
- // Copy constructor definition
- CMessage(const CMessage& aMess)
- {
- cout << "CMessage copy constructor called." << endl;
- text = aMess.text;
- }
- // Move constructor definition
- CMessage(CMessage&& aMess)
- {
- cout << "CMessage move constructor called." << endl;
- text = aMess.text;
- }
- };
消息文本现在存储为CText类型的对象,CMessage类的成员函数也进行了相应的修改。需要注意的是,CMessage类具有rvalue引用版本的复制构造函数和赋值运算符,因此在可能的情况下,它应该是移动而不是创建新对象。下面是CText类的定义:
- class CText
- {
- private:
- char* pText;
- public:
- // Function to display text
- void ShowIt() const
- {
- cout << pText << endl;
- }
- // Constructor
- CText(const char* pStr="No text")
- {
- cout << "CText constructor called." << endl;
- size_t len(strlen(pStr)+1);
- pText = new char[len]; // Allocate space for text
- strcpy_s(pText, len, pStr); // Copy text to new memory
- }
- // Copy constructor definition
- 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);
- }
- // Move constructor definition
- CText(CText&& txt)
- {
- cout << "CText move constructor called." << endl;
- pText = txt.pText;
- txt.pText = nullptr;
- }
- // Destructor to free memory allocated by new
- ~CText()
- {
- cout << "CText destructor called." << endl; // Just to track what happens
- delete[] pText; // Free memory
- }
- // Assignment operator for CText objects
- CText& operator=(const CText& txt)
- {
- cout << "CText assignment operator function called." << endl;
- if(this != &txt) // Check addresses not equal
- {
- delete[] pText; // Release memory for 1st operand
- size_t len(strlen(txt.pText)+1);
- pText = new char[len];
- // Copy 2nd operand string to 1st
- strcpy_s(this->pText, len, txt.pText);
- }
- return *this; // Return a reference to 1st operand
- }
- // Move assignment operator for CText objects
- CText& operator=(CText&& txt)
- {
- cout << "CText move assignment operator function called." << endl;
- delete[] pText; // Release memory for 1st operand
- pText = txt.pText;
- txt.pText = nullptr;
- return *this; // Return a reference to 1st operand
- }
- // Overloaded addition operator
- CText operator+(const CText& txt) const
- {
- cout << "CText add operator function called." << endl;
- size_t len(strlen(pText) + strlen(txt.pText) + 1);
- CText aText;
- aText.pText = new char[len];
- strcpy_s(aText.pText, len, pText);
- strcat_s(aText.pText, len, txt.pText);
- return aText;
- }
- };