在传递变量时,按值传递变量、按地址传递和按指针传递差别不是很大,但是如果传递的是对象时,三者的差别很大。
这是因为,按值传递在向函数传递一个对象时,会像传递变量那样在外部函数内建立一个该对象的拷贝,而从函数返回一个对象时,也要建立这个被返回的对象的一个拷贝。
假如该对象的数据非常多时,这种拷贝带来的内存开销是相当可观的。比如说,该对象拥有1000多个double型成员变量,每个double型变量占据8个字节,1000个就要占据8000个字节,每次通过值传递的方式给函数传递该对象,都要在栈中复制该对象,占用8000个字节的栈内存,而返回该对象,又要在栈中复制一次,这样就又要占用8000个字节的内存空间。我们知道,栈的内存只有2M大小,8000个字节占用8K,那么仅仅传递该对象就占用了栈内16k字节的空间。并且别的对象想要访问该对象的8000个数据成员的时候,也要同样采取复制的方式,那么系统的开销将无法估算了。
然而,按值传递所付出的开销远不止如此,由于在传递过程中需要复制对象,因此会默认调用复制构造函数,该函数的作用就是创建某个对象的临时副本。
而当函数返回时,传递该对象时创建的该对象的副本会被删除,这时候又会自动调用该对象的析构函数来释放内存。假设返回的仍然是该对象,并且仍旧采用按值传递的方式,那么就又会调用复制构造函数建立一个该对象的临时副本,当该值被成功返回给调用程序后,然后再调用该对象的析构函数删除临时拷贝,并释放内存。
代码如下:
#include <iostream>
using namespace std;
class A
{
public:
A(){cout<<"构造函数被调用..."<<endl;}
A(A&){cout<<"复制构造函数被调用。。。"<<endl;} //复制构造函数
~A(){cout<<"析构函数被调用..."<<endl;}
};
A func(A one)
{
return one;
}
int main()
{
A a;
func(a);
return 0;
}
运行结果如下:
构造函数被调用...
复制构造函数被调用。。。
复制构造函数被调用。。。
析构函数被调用...
析构函数被调用...
析构函数被调用...