C++学习6-变量生命周期

北慕城南 提交于 2020-02-23 01:31:30

变量生命周期

int main()
{
    Test t1(10);
    Test t2; // => 不要写成 test t2() 会变成函数的声明
    Test t3(t2);
    Test t4 = t3;//t3拷贝构造t4

    // Test t5(40);
    Test t5 = Test(40); // 生成临时对象 Test(int)
/*
Test t5 = Test(40)
等于  Test t5(40)--
是用临时对象 拷贝构造同类型的对象 临时对象不产生 直接构造对象即可
不是 :生成临时对象  拷贝构造t5  析构临时对象
*/
    cout << "-----------" << endl;


    t2 = t3;// 赋值
    t2 = Test(50); // 显式生成临时对象
//显式生成临时对象  这个临时对象是要产生的 然后给t2赋值 再析构临时对象
    t2 = 50; // 隐式生成临时对象 int -> Test(int)
//把其他类型转成类的类型 要看这个类有没有一个构造函数接收这个类型来生成临时对象

    cout << "-----------" << endl;
    return 0;
}

介绍变量生命周期,先看看下面程序中函数对象的调用情况
原本程序:

Test GetTestObject(Test t)
{
    int val = t.getData();
    Test tmp(val);
    return tmp;
}
int main()
{
    Test t1;
    Test t2;
    t2 = GetTestObject(t1);
    return 0;
}

函数调用情况:
构造t1
构造t2
t1拷贝构造临时形参对象t
构造tmp
tmp拷贝构造临时对象
析构tmp
析构形参对象t
临时对象赋值给t2
析构临时对象
析构t2
析构t1

优化1.函数调用传参数,如果是对象,形参按引用来接收
优化2.函数返回对象值的时候,应该返回临时对象

下面程序体现:

class Test
{
public:
    Test(int data=10):ma(data)
    {
        cout << "Test(int)" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
    Test(const Test &src) :ma(src.ma)
    {
        cout << "Test(const Test&)" << endl;
    }
    void operator=(const Test &src)
    {
        cout << "operator=" << endl;
        ma = src.ma;
    }
    int getData() { return ma; }
private:
    int ma;
};
Test GetTestObject(Test &t)
{
    int val = t.getData();
    return Test(val); // 生成临时对象
}
int main()
{
    Test t1;
    Test t2;
    t2 = GetTestObject(t1);
    return 0;
}

所以传值得时候传引用 可以少两个函数: 拷贝构造和析构
函数调用情况:
构造t1
构造t2
构造带整型参数的临时对象-----(因为用临时对象 拷贝构造同类型的对象 临时对象不产生 直接构造对象即可)
临时对象赋值给t2
析构临时对象
析构t2
析构t1

注意:用临时对象 拷贝构造同类型的对象的时候才优化

优化3.应该以初始化的方式接收返回值是临时对象的返回

Test GetTestObject(Test &t)
{
    int val = t.getData();
    return Test(val); // 生成临时对象
}
int main()
{
    Test t1;
    Test t2 = GetTestObject(t1);
    return 0;
}

函数调用情况:
构造t1
构造t2------刚刚是赋值 所以要产生临时对象 而现在是直接用临时对象构造同类型的对象 所以直接构造 临时对象完全不用产生
----所以应该以初始化的方式接收返回值是临时对象的返回
析构t2
析构t1

优化4.写右值引用
因为给tmp构造了10000*4的空间 将数据拷贝进来 给临时对象 又析构掉tmp
费老大劲构造出来又析构掉
对于局部的临时的对象给外部对象拷贝构造或者重载 会匹配带右值引用参数的拷贝构造和重载函数

class Test
{
public:
    Test()
    {
        mptr = new int[10000];
        cout << "Test()" << endl;
    }
    ~Test()
    {
        delete[]mptr;
        cout << "~Test()" << endl;
    }
    Test(const Test &src)
    {
        cout << "Test(const Test&)" << endl;
        /*mptr = new int[10000];
        for (int i = 0; i < 10000; ++i)
        {
            mptr[i] = src.mptr[i];
        }*/
    }
    //main栈临时对象  tmp
    Test(Test &&src) // 带右值引用参数的拷贝构造
    {
        cout << "Test(Test&&)" << endl;
        mptr = src.mptr;
        src.mptr = nullptr;
    }

    void operator=(const Test &src)
    {
        cout << "operator=" << endl;
        if (this == &src)
            return;


        delete[]mptr;


        mptr = new int[10000];
        for (int i = 0; i < 10000; ++i)
        {
            mptr[i] = src.mptr[i];
        }
    }
    void operator=(Test &&src) // 带右值引用参数的赋值函数
    {
        cout << "operator=(Test&&)" << endl;
        if (this == &src)
            return;

        delete[]mptr;

        mptr = src.mptr;
        src.mptr = nullptr;
    }
private:
    int *mptr;
};


Test GetTestObject(Test &t)
{
    Test tmp;
    return tmp;
}
int main()
{
    Test t1;
    Test t2;
    t2 = GetTestObject(t1);
    return 0;
}

右值引用中
慎用memcpy代替for

memcpy(ptr,t.ptr,4*1024)

memcpy做的是浅拷贝,如果对象里有占用外部资源,用这个就不对 for做的会调用本身的构造或者重载 但是memcpy不会

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!