• 移动语义 && 函数调用过程中的 lvalue


    当以一个函数内的临时变量对象作为另一个函数的形参的时候,原函数内的临时对象即 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 函数问题。

  • 相关阅读:
    htmlspecialchar()
    LINUX权限bash: ./startup.sh: Permission denied
    str_replace()
    centos安装教程
    给准备做软件测试的新手们的一点个人心得
    TFS安装与管理
    TFS使用指南
    实现对n个数字随机排序,并循环输出100次
    SSM启动Tomcat报错ERROR [localhoststartStop1] Context initialization failed
    同济大学软件学院万院长谈择业
  • 原文地址:https://www.cnblogs.com/yunqie/p/5954725.html
Copyright © 2020-2023  润新知