1、C++中返回值优化问题
返回值优化(Return Value Optimization,简称RVO),是这么一种优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消 耗一个构造函数(Constructor)的调用、一个复制构造函数的调用(Copy Constructor)以及一个析构函数(Destructor)的调用的代价。而如果稍微做一点优化,就可以将成本降低到一个构造函数的代价。
详细说明:C++中临时对象及返回值优化
2、拷贝构造函数的调用
首先,关闭返回值优化:
然后,执行以下函数:
#include <iostream>
#include <string.h>
class student {
public:
// 普通构造函数
student(int i, char* c, int a, float s) {
std::cout << "Constructing..." << std::endl;
id = i;
age = a;
score = s;
name = new char[strlen(c) + 1]; //申请堆空间
if (name != 0) strcpy(name, c);
}
// 显示声明拷贝函数,自定义实现深拷贝
student(const student& s) {
std::cout << "Copy Constructing..." << std::endl;
id = s.id; //一般成员简单复制
age = s.age;
score = s.score;
name = new char[strlen(s.name) + 1]; //先申请堆空间
if (name != 0) strcpy(name, s.name); //复制字符串
};
~student() {
std::cout <<"Destructing..."<< std::endl;
delete []name;
}
int getid() {
return id;
}
char* getName() {
return name;
}
private:
int id;
char* name;
int age;
float score;
};
// 函数返回值是类对象,函数执行完成返回调用时,系统会自动调用拷贝构造函数
student g() {
student s1(10, (char*)"Lina", 18, 86);
return s1;
}
// 如果函数的形参是类的对象,调用函数时,用实参的值初始化形参时,系统会自动调用拷贝构造函数
void print_1(student s) {
std::cout << "学号:" << s.getid() << std::endl;
}
int main() {
student s1(10, (char*)"Wang", 18, 86); //创建和初始化对象
std::cout << std::endl;
// 第一种情况,用s1初始化s2。第一次调用拷贝构造函数
student s2 = s1;
std::cout << std::endl;
// 第二种情况,对象s2作为print_1的实参。第二次调用拷贝构造函数
print_1(s2);
std::cout << std::endl;
// 第三种情况,函数的返回值是类对象,函数返回时调用拷贝构造函数
//s2 = g();
student s3 = g();//s3是要先分配,所以执行的是拷贝构造,不是赋值
std::cout << s3.getName() <<std::endl;
//禁止返回值优化以后,g()return的时候调用了显式的拷贝构造函数,构造了Ts,“=”采用了浅拷贝,拷贝完,Ts释放。
//所以程序结束后再释放 s2报错。
//注意::所有存在堆空间的类,必须用深拷贝!!任何地方不允许出现钱拷贝。
std::cout << "happy" <<std::endl;
return 0;
//getchar();
}
当输入为:
student s3 = g();
std::cout << s3.getName() <<std::endl;
“=” 用来初始化,执行的是显式拷贝构造函数,也就是深拷贝。
输出:
Constructing... //s1调用构造函数
Copy Constructing... //用s1初始化s2。第一次调用拷贝构造函数
Copy Constructing... //对象s2作为print_1的实参。第二次调用拷贝构造函数
学号:10
Destructing...//析构临时变量
Constructing... //函数里的临时对象s1调用构造函数
Copy Constructing... //函数的返回值是类对象,函数返回时调用拷贝构造函数
Destructing...//函数里的临时对象s1析构
Copy Constructing...//返回值临时对象初始化s3,调用拷贝构造函数
Destructing...//返回值临时对象析构
Lina
happy
Destructing...//s1 析构
Destructing...//s2 析构
Destructing...//s3 析构
Program ended with exit code: 0
当输入为:
s2 = g();
std::cout << s2.getName() <<std::endl;
“ = ” 用来赋值,执行的是浅拷贝。也就是返回值的指针和s2的指针指向同一块内存区域。所以当返回值对象被析构以后,再执行s2的析构,释放的空间已经不存在!
输出:
Constructing... //s1调用构造函数
Copy Constructing... //用s1初始化s2。第一次调用拷贝构造函数
Copy Constructing... //对象s2作为print_1的实参。第二次调用拷贝构造函数
学号:10
Destructing...//析构临时变量
Constructing... //函数里的临时对象s1调用构造函数
Copy Constructing... //函数的返回值是类对象,函数返回时调用拷贝构造函数
Destructing... //函数里的临时对象s1析构
Destructing...//返回值临时对象析构
Lina
happy
Destructing...//s1 析构