zoukankan      html  css  js  c++  java
  • 移动语义 && 函数调用过程中的 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 函数问题。

  • 相关阅读:
    php增加自动刷新当前页面
    liunx环境下安装mysql5.7及以上版本
    mysql的主从级联复制的配置
    windowns常用命令
    liunx之使用(mount)挂载技术
    在burpsuite中为什么不能选中设置好的代理?
    c++中向任意目录下写文件
    Hbase——JavaAPI操作笔记
    每周总结(6)(补)
    每周总结(5)
  • 原文地址:https://www.cnblogs.com/yunqie/p/5954725.html
Copyright © 2011-2022 走看看