变量生命周期
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不会
来源:CSDN
作者:李承承sunshine
链接:https://blog.csdn.net/sunshine612/article/details/104450249