浅拷贝和深拷贝
浅拷贝:
如果用默认的拷贝构造函数去拷构造有指针类型的成员变量的对象,只是会简单的再创建一个指针变量,指针变量的值任然拷贝之前的值;会使两个对象的指针地址也是一样的,也就是说这两个对象的指针成员变量指向的是相同的地址,因为指向同一块内存,容易产生堆区内存重复释放的问题
深拷贝:
深拷贝需要重写拷贝构造和赋值构造函数,重新在堆区申请内存
临时对象
C++ 中容易写出一些代码,这些代码会在程序员不知情的情况下产生一些临时对象,导致临时对象会调用拷贝构造函数,赋值运算符,析构函数,假如该对象还有继承的话,也会调用父类的拷贝构造函数,赋值运算赋函数等,这些临时对象所调用的函数,都是不必要的开销,下面分类讨论下面几种情况
对象做为函数形参
结论:
对象本身做为函数形参,以值传递的方式给函数传参这种方式会直接调用对象的拷贝构造函数,生成一个临时对象传参给函数
当临时对象销毁时候,也是函数形参销毁,也是函数执行完后,就会调用该临时对象的析构函数。此时,无论是调用拷贝构造函数和析构函数,都是额外的开销
代码验证
略,可以定义类时在拷贝构造和析构函数中打印,查看结果
原理
函数调用本身是单向的值传递,在调用函数的时候,实际传递的是实参的复制品,是一个临时对象,不是外面函数的实参,此时在函数内部修改对象,外面的对象本身没有变化
解决方案
只要把值传递的方式修改为引用传递的方式即可
类型转换为临时对象
这种方式就是并且把类型转化前的对象当作了形参传递给构造函数,生成临时对象
定义一个类,重载有一个uint32 类型参数的构造函数和无参构造函数,然后调用形式如下:
{
baseClass p;
p = 1000;
}
原理
其实是由于 p = 1000 这句引起的,这里p的类型为 baseClass,而 1000为 int 类型,很明显类型不一致
编译器其实偷偷的进行了类型转换,看编译器的调用都可以发现,其实就是创建一个临时对象,这个临时对象调用了有参构造函数,并且把 这个1000 作为形参,传入有参构造函数,当这个函数调用结束后,对象也就销毁了,所以临时对象会调用析构函数
解决方案
只要把单参数构造函数的复制(复制)语句,改为初始化语句
baseClass p = 1000
函数返回对象
在函数返回对象时候,会创建一个临时对象接收这个对象;从而调用了拷贝构造函数和析构函数
当调用函数时,没有接收返回值时候,就会调用返回值析构函数,因为没有人接收返回值了,自然而然析构了
当调用有接收返回值时候,这个时候,并不会多调用一次析构函数,而是直接把临时对象返回值,给了接受返回值的变量来接收
baseClass testfunction() {
baseClass a; //baseClass constructor
return a; // baseClass copy constructor
}
testfunction();//baseClass destructor
上面的函数会调用
demoMain Run ....
baseClass constructor
baseClass copy constructor
baseClass destructor //临时对象的析构
baseClass destructor// 返回值对象的析构
如果修改为下面的调用形式:
baseClass p = testfunction();//baseClass destructor
cout << "output end" << endl;
baseClass constructor
baseClass copy constructor
baseClass destructor //临时对象析构
output end
baseClass destructor //返回值对象析构
解决方案:
当我们在接收函数返回的对象时候,可以用右值引用接收,因为该函数返回值是一个临时变量,用一个右值引用接收它,使得它的生命周期得以延续,这样就少调用一次析构函数的开销(普通的对象接收也是可以)
当我们在设计函数里的return 语句中,不是返回创建好的对象,而是返回我们临时创建的对象,即使用retturn 类类型(形参); 这个时候,就可以直接避免 return 对象;返回时候又要调用多一次构造函数
baseClass testfunction() {
#if 0
baseClass a; //baseClass constructor
return a; // baseClass copy constructor
#else
return baseClass();
#endif
}
{
baseClass p = testfunction();//baseClass destructor
cout << "output end" << endl;
}
网友评论