按值传递
按值传入
C中传参方法就两个,一个是按值传递,一个是传指针。CPP当然也继承了它爹C的性质。不过按值传递是怎么个传递法,在CPP中又是个什么情况,很多人都没搞明白,下面我们来看看,类的按值传递问题
//使用全局变量记录生成个数,让运行更清晰
int buildcont = 0;
//按值传递测试
struct test
{
int a;
test() { a = buildcont++; cout << "test"<<a<<" is build!" << endl; }
test(const test& other) { a = buildcont++; cout << "test" << a << " is build by copy!" << endl; }
//移动构造函数
//test(test&& other)noexcept { a = buildcont++; cout << "test" << a << " is build by movebild" << endl; }
~test(){ cout << "test "<<a <<" is destory!" << endl; }
};
void testfun1(test aint)
{
return;
}
int main()
{
test test0;
cout << "------------" << endl;
testfun1(test0);
cout << "------------" << endl;
return 0;
}
运行结果
test0 is build!
------------
test1 is build by copy!
test 1 is destory!
------------
test 0 is destory!
- 第一个build是我们
test test0;
void testfun1(test aint)
当你按值把对象传到函数里面去,实际上,是调用了一次拷贝构造函数,生成了一个函数栈内存中的test对象test1(镜像一下,一般不影响原值(如果你的拷贝构造函数是正常的话))- 函数运行结束,自动调用析构函数,报出test1销毁。返回主函数
- 主函数运行到
return 0;
自动销毁所有对象,test0的析构被调用,程序结束
按值传出
test testfun2(test aint)
{
cout << "-----tag here-----" << endl;
return aint;
}
int main()
{
test test0;
cout << "------------" << endl;
testfun2(test0);
cout << "------------" << endl;
return 0;
}
运行结果
test0 is build!
------------
test1 is build by copy!
-----tag here-----
test2 is build by movebild
test 1 is destory!
test 2 is destory!
------------
test 0 is destory!
分析
test1 is build by copy!
这是按值传递,拷贝构造运行,将test0的副本(记为test1)加入函数testfun2的栈中-----tag here-----
函数体运行的结果test2 is build by copy!
这句话是**return aint;**的运行结果,实质是将栈中的test1做返回值。但是函数栈要被销毁(运行到结尾了),所以再次调用拷贝构造函数,把test1的副本传到主函数中(这是一个无名变量,记为test2)- 指出,这里如果不写移动构造函数确实是copy,如果写了那就是调用移动构造函数,报为:
test2 is build by movebuild
CPP会自动选择最有利的构造函数
- 指出,这里如果不写移动构造函数确实是copy,如果写了那就是调用移动构造函数,报为:
test1 is destory!
这第一个销毁,销毁的是test1,它在testfun2的栈中,函数运行完成,分配的栈内存被回收,自然被销毁test2 is destory!
这第二个销毁,销毁的是返回到主函数中的无名对象(test2),因为它的生命只在testfun2(test0);
这个语句,运行到下一个语句的时候test2就被销毁了(不理解?看看下一个例子)。
移动构造
移动构造函数是C11提出的特性,它的特点是把无名变量的资源重新利用生成具名对象,而无需再次从0构造,让CPP更快,下面是函数格式
test(test&& other)noexcept {
a = buildcont++;
cout << "test" << a << " is build by movebild" << endl; }
下面是C中常见的新手的写法,基本上都是按值传递,我们可以看看运行结果,不必要的构造了几个对象
int main()
{
test test0;
cout << "------------" << endl;
test temp=testfun2(test0);
cout << temp.a << endl;
cout << "------------" << endl;
return 0;
}
运行结果
test0 is build!
------------
test1 is build by copy!
-----tag here-----
test2 is build by movebild
test 1 is destory!
2
------------
test 2 is destory!
test 0 is destory!
test2 is build by movebild
这个语句是test temp=testfun2(test0);
在主函数中的运行结果,它这里直接把test1的值移动给temp(这里应该有一步优化)- 可见,CPP如果按值传递,没有优化的话,要多损耗两个对象的性能(VS 会优化为损耗1个对象的性能,就是拷贝到函数的栈的性能【这是最基本的性能损耗了】)