C++中临时对象的产生与优化
来源:互联网 发布:mac mini win10 编辑:程序博客网 时间:2024/06/10 16:30
C++中临时对象的产生与优化
本文主要介绍c++中临时对象产生的几种情况,同时介绍避免的策略。由于在C++中对象的创建和消除会调用该对象对应的构造和析构函数,是一个相对比较耗时的操作,从程序效率角度来说我们应该了解并消除临时对象;又如果类中有指针,更应该了解临时对象,避免指针悬挂和内存泄露等问题。
一、拷贝构造函数和赋值操作符
在深入讨论临时对象之前来看一下拷贝构造函数和赋值操作符,为什么呢?一般而言,临时对象的产生一般对象的赋值或者拷贝,这时就需要了解拷贝操作和赋值操作。
1. 拷贝操作:对象在定义时进行的初始化操作,此时调用的是拷贝构造函数完成。
2. 赋值操作:对象定以后的赋值操作,此时调用的是赋值操作符完成。
那么什么时候进行拷贝操作,什么时候进行赋值操作呢?如定义所示一个变量在第一次定义时进行的操作一般为拷贝操作,例如 A a; A a2 = 1; A a3(a2); A a4 = a3; 进行赋值操作的前提是变量左值已经定义,例如A a; A b; b=a;
// 验证拷贝构造函数 和 赋值操作符#include <iostream> class TestObject { public: TestObject() { std::cout << "TestObject() is called:" << con_call_num_++<< std::endl; } TestObject(int _x) { x_ = _x; std::cout << "TestObject(int) is called:" << con_call_num_++<< std::endl; } TestObject (TestObject & to) { x_ = to.x_; std::cout << "TestObject(TestObject) is called:" << ccon_call_num_++ << std::endl; } TestObject (const TestObject& to) { x_ = to.x_; std::cout << "TestObject(const TestObject) is called:" << ccon_call_num_++ << std::endl; } TestObject &operator =(const TestObject& to) { if (&to == this) return *this; x_ = to.x_; std::cout << "operator =(const) is called:" << equal_call_num_++ << std::endl; return *this; } TestObject &operator =(TestObject& to) { if (&to == this) return *this; x_ = to.x_; std::cout << "operator =() is called:" << equal_call_num_++ << std::endl; return *this; } ~TestObject() { std::cout << "~TestObject() is called:" << des_call_num_++ << std::endl; } private: int x_; static int con_call_num_; static int ccon_call_num_; static int equal_call_num_; static int des_call_num_;}; int TestObject::con_call_num_ = 0;int TestObject::ccon_call_num_ = 0;int TestObject::equal_call_num_ = 0;int TestObject::des_call_num_ = 0; int main() { // copy TestObject to_1; TestObject to_2(1); TestObject to_3 = 1; TestObject to_4 = to_2; TestObject to_5(to_4); // assign to_1 = to_2; return 0;}
其对应的输出为:
TestObject() is called:0TestObject(int) is called:1TestObject(int) is called:2TestObject(TestObject) is called:0TestObject(TestObject) is called:1operator =() is called:0~TestObject() is called:0~TestObject() is called:1~TestObject() is called:2~TestObject() is called:3~TestObject() is called:4
从输出中可以看出带有”=“进行的不一定是赋值操作符,也有可能是拷贝构造函数。另外解决对象的深浅拷贝问题,要同时注意重载拷贝构造函数和赋值操作符。记住默认的拷贝和赋值操作均为浅拷贝。
二、临时对象的产生与优化
总体来说,临时对象产生主要有以下三种情况,
1. 以值的方式给函数传参
2. 隐式类型转换
3. 函数返回一个对象时
2.1 以值的方式给函数传参
临时对象产生点在于给函数参数传值时,先生成该对象的临时对象,调用拷贝构造函数进行拷贝。消除方法是尽量使用引用或者传指针的方式。
void Fun1(TestObject to) { std::cout << "Fun1(TestObject) is called" << std::endl;}void Fun1_1(TestObject & to) { std::cout << "Fun1_1(TestObject&) is called" << std::endl;}int main() { TestObject to_2; std::cout << "-----Test type 1-------" << std::endl; Fun1(to_2); Fun1_1(to_2); return 0;}
产生输出如下:
TestObject() is called:0-----Test type 1-------TestObject(TestObject) is called:0Fun1(TestObject) is called~TestObject() is called:0Fun1_1(TestObject&) is called~TestObject() is called:1
说明:在函数传入参数时调用的是拷贝构造函数,并且临时对象的释放在一个完整语句结束时释放,即第一个分号之后。
2.2 隐式类型转换
临时对象的产生点在于发送隐式类型转换时,先进行类型转换,在进行赋值。消除方法是尽量定义即进行初始化。
int main() { TestObject to_2; std::cout << "-----Test type 1-------" << std::endl; Fun1(to_2); Fun1_1(to_2); std::cout << "-----Test type 2-------" << std::endl; TestObject to_3; to_3 = 1; TestObject to_4 = 1; return 0;}
输出结果为:
-----Test type 1-------TestObject(TestObject) is called:0Fun1(TestObject) is called~TestObject() is called:0Fun1_1(TestObject&) is called-----Test type 2-------TestObject() is called:1TestObject(int) is called:2operator =(const) is called:0~TestObject() is called:1TestObject(int) is called:3~TestObject() is called:2~TestObject() is called:3~TestObject() is called:4
在进行隐式类型转换进行的操作为:先调用构造函数生成临时对象,在进行赋值操作。
2.3函数返回一个对象时
临时对象产生点在于返回对象时先生成一个临时对象,在进行拷贝操作,消除方法是尽量不要返回对象,如果需要返回,可以考虑进行传入指针的方式进行赋值。
TestObject Fun2_1() { std::cout << "Fun2_1() is called" << std::endl; return 1;}TestObject Fun2_2() { std::cout << "Fun2_2() is called" << std::endl; TestObject to; to.set_x(1); return to;}int main() { /* TestObject to_2; std::cout << "-----Test type 1-------" << std::endl; Fun1(to_2); Fun1_1(to_2); std::cout << "-----Test type 2-------" << std::endl; TestObject to_3; to_3 = 1; TestObject to_4 = 1; */ std::cout << "-----Test type 3-------" << std::endl; Fun2_1(); Fun2_2(); return 0;}
输出结果为:
-----Test type 3-------Fun2_1() is calledTestObject(int) is called:0~TestObject() is called:0Fun2_2() is calledTestObject() is called:1~TestObject() is called:1
可以看到没有调用拷贝构造函数,主要因为现在编译器比较智能了能够对类似情况进行优化。
C++中的返回值优化(returnvalue optimization)
返回值优化(Return ValueOptimization,简称RVO),是这么一种优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消耗一个构造函数(Constructor)的调用、一个复制构造函数的调用(Copy Constructor)以及一个析构函数(Destructor)的调用的代价。
三、总结
理论结合实践才是真理。由于编译器的不同,产生结果可能会不同,在实际开发中遇到不确定的情况,多写测试用例。
- C++中临时对象的产生与优化
- C++中临时对象的产生与运用
- 临时对象的产生与运用
- C++中临时对象的产生
- 编译器产生的临时对象
- more effective c++(临时对象的返回值优化)
- 关于c++临时对象产生的规则
- C++产生的临时对象引用
- 临时对象如何产生
- 临时对象与返回值优化
- C++ 临时对象的创建与防止
- 与临时对象的斗争
- 避免产生临时(隐式)对象
- MFC临时对象的所产生的BUG
- 浅析C++临时对象的产生相关问题
- 浅析C++临时对象的产生相关问题
- 浅析C++临时对象的产生相关问题
- C++中临时对象及编译器对返回值优化的手段
- join
- GCC生成汇编文件解析
- 设置mysql最大连接数的方法
- Android-通过URL获取网络资源 Json 字符串
- 今天的面试题--操作ArrayList。
- C++中临时对象的产生与优化
- c++ 初学 派生类到基类转换的可访问性
- css选择器详解
- 日志相关
- 20-可变参数
- 【goldengate】表列数超过33个
- android:minSdkVersion 之我见
- 人体
- Cocos2d-x中编辑框CCEditBox的使用