• 剖析——移动构造函数


    移动构造函数应用的场景????

    答:有时候我们会遇到这样一种情况,我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a的空间呢?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。

    例子示下:

    #include<string>
    #include<vector>
    using namespace std;
    
    class String;
    ostream& operator<<(ostream& out, String& s);
    class String
    {
    public:
        friend ostream& operator<<(ostream& out, String& s);
    public:
        String(const char* data = "")
        {
            if (data == NULL)
            {
                m_data = new char[1];
                m_data[0] = '';
            }
            else
            {
                m_data = new char[strlen(data) + 1];
                strcpy(m_data, data);
            }
            cout << "constructor execute..." << endl;
        }
        String(String &&s)noexcept
        {
            cout << "move constructor execute..." << endl;
            m_data = NULL;
            this->m_data = s.m_data;
            s.m_data = NULL;
        }
        ~String()
        {
            cout << this<<"free execute..." << endl;
            if(m_data != NULL)
                delete[] m_data;
        }
    private:
        char* m_data;
    };
    
    ostream& operator<<(ostream& out, String& s)
    {
        out << s.m_data;
        return out;
    }
    int main()
    {
        String s = "hello";
        vector<String> vs(1);
        vs.push_back(std::move(s));
        return 0;
    }

    执行结果:

    解析运行结果:

    1、第一个 “默认构造函数” 是因为vector<String> vs(1) , 所以事先使用默认构造函数构造了一个Test对象

    2、第二个 “默认构造函数” 是因为Test t ,使用默认构造函数构造了一个对象

    3、第三个 “移动构造函数” 大多数人会以为是 vec.push_back(std::move(s)) ,push_back 导致对象的移动而输出的。具体的原因其实是由于重新分配内存而导致的,我们的 vector 对象 vs 初始的容量只有 1 ,且里面已经有一个对象了,就是vector<Test> vs(1)的时候创建的,所以再向vs里面添加String对象时,就会导致vs重新分配内存。由于vs中的对象定义了移动构造函数且是可用的(因为我们将其声明为了noexcept),所以就会调用移动构造函数将vs中原始的那个对象移动到新的内存中,从而输出 “移动构造函数”。

    4、第四个 “移动构造函数” 才是因为String对象 t 被移动到vector 对象 vs 新的空间而输出的

    5、第五个 “析构函数” 是因为重新分配内存后,原来的内存将被销毁,所以输出一个“析构函数”

    6、后面三个 “析构函数” 是因为执行了return 0, 内存被释放,vs 和 s 都被析构,所以输出三个 “析构函数

    注意:

    第四行的输出由 “移动构造函数” 变成了 “拷贝构造函数” ,原因是:

    由于我们的移动构造函数没有声明为noexcept,所以我们的移动构造函数就会被认为是可能抛出异常,所以在重新分配内存的过程中,vs对象就会使用拷贝构造函数来“移动”对象(这里说的移动其实是拷贝,并不是移动),所以就输出了“拷贝构造函数”。

  • 相关阅读:
    学用Fireworks中的特效1 建站之家
    网页页面尺寸一般设置多大才合适
    什么是哲学为基础的设计模式?
    10个步骤让你成为高效的Web开发者
    到移动开发大会 听《植物大战僵尸》成功秘诀
    [转]设置IE背景色保护你的眼睛视力_鹤壁吧_贴吧
    乔布斯在斯坦福大学演讲时说
    XQ4 logo1.html
    你是一位领导者吗?企业领导者必须具备的10种才能
    对不起,我已爱上你
  • 原文地址:https://www.cnblogs.com/single-dont/p/11328524.html
Copyright © 2020-2023  润新知