1. 临时对象与编译优化
C++ 中 临时对象,又称为无名对象,临时对象主要出现在如下场景:
- 构造函数作为隐式类型转换时,会创建临时对象,用作实参传递给函数;
#include <iostream>
using namespace std;
class Integer
{
public:
Integer(int i) : m_ival(i) //没有 explicit 显示转换限制 表示可以隐式转换 int ==> Integer
{
cout << "Interger (int i) construct:" << ++m_constructs << endl;
}
explicit Integer(double d) : m_dval(d)
{
cout << "Integer(double d) construct:" << ++m_constructs << endl;
}
Integer(const Integer &integer)
{
cout << "Interger copy construct:" << ++m_copy_constructs << endl;
}
~Integer()
{
cout << "Interger desconstruct:" << ++m_desconstructs << endl;
}
private:
int m_ival;
double m_dval;
static int m_constructs;
static int m_desconstructs;
static int m_copy_constructs;
};
int Integer::m_constructs = 0;
int Integer::m_desconstructs = 0;
int Integer::m_copy_constructs = 0;
void Func(Integer integer)
{
cout << "--Func--" << endl;
}
int main()
{
int i = 10;
Func(i);
return 0;
}
/*g++ -g main.cpp -fno-elide-constructors 忽略编译器优化
输出信息:
Interger (int i) construct:1
Interger copy construct:1
--Func--
Interger desconstruct:1
Interger desconstruct:2
首先 Func(i); 传递的参数类型为int != Integer;
通过构造函数 Integer(int i) 构造一个临时对象 template_object; ==> Interger (int i) construct:1
在调用Func(Integer integer)时,将临时对象 template_object 赋值给 integer ; ==> Interger copy construct:1
然后Func(i)执行输出; ==> --Func--
Func(i)执行完毕时 临时对象析构; ==> Interger desconstruct:1
Func(i)执行完毕时 integer析构: ==> Interger desconstruct:2
*/
- 建立一个没有命名的非堆对象,也就是无名对象时,会产生一个临时对象;
如:
类名(<参数列表>); //创建了一个临时对象
- 函数返回一个对象时,会产生临时对象,函数中的返回值会以值拷贝的形式拷贝到被调函数的栈中的一个临时对象;
Integer Func()
{
Integer inter(5);
return inter;
}
int main()
{
Integer re=Func();
return 0;
}
/*
Interger (int i) construct:1
Interger copy construct:1
Interger desconstruct:1
Interger copy construct:2
Interger desconstruct:2
Interger desconstruct:3
1. main 中调用Func();
1. Integer inter(5); 调用构造函数 Integer(int i) ==> Interger (int i) construct:1;
2. return inter; 会将 Func 函数栈区的 inter 保存到一个临时对象 template_object 中:==> Interger copy construct:1
3. Func()函数执行完毕后,inter析构: ==> Interger desconstruct:1
4. 临时对象 template_object 复制到 re 中: ==> Interger copy construct:2
5. 临时对象 template_object 析构; ==> Interger desconstruct:2
6. main 函数结束 re 析构; ==> Interger desconstruct:3
*/
2. 编译优化 -fno-elide-constructors
由于产生临时对象不仅会占用计算机资源(多次复制),而且有的时候还会导致程序错误,所以编译器会优化程序,尽可能减少临时对象的产生.
-fno-elide-constructors:
The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases.
在C++11右值引用出现之前,C++的临时对象问题带来了非常大的性能开销,而编译器的这种优化,大大减少了很多无谓的copy;
3. 例子
#include <iostream>
using namespace std;
class HasPtrMem
{
public:
HasPtrMem() : d(new int(0))
{
cout << "Construct: " << ++n_cstr << endl;
}
HasPtrMem(const HasPtrMem &h) : d(new int(*h.d))
{
cout << "Copy construct: " << ++n_cptr << endl;
}
~HasPtrMem()
{
cout << "Destruct: " << ++n_dstr << endl;
}
int *d;
static int n_cstr;
static int n_dstr;
static int n_cptr;
};
int HasPtrMem::n_cstr = 0;
int HasPtrMem::n_dstr = 0;
int HasPtrMem::n_cptr = 0;
HasPtrMem GetTemp()
{
return HasPtrMem();
}
int main()
{
HasPtrMem object = GetTemp();
return 0;
}
/* g++ -g main.cpp -fno-elide-constructors 忽略编译器优化
*
Construct: 1
Copy construct: 1
Destruct: 1
Copy construct: 2
Destruct: 2
Destruct: 3
1. 调用 GetTemp() 过程中会创建生成两次临时对象 :
1. HasPtrMem(); ==> 会创建临时对象 template_object1 ==> Construct: 1
2. return ,返回临时对象 template_object1 到 tempate_object2 , 然后析构 template_object1;
3. 然后将 template_object2 赋值 给 object后,template_object2 析构;
4. main函数结束, object 析构;
*/
/* g++ -g main.cpp 未忽略编译器优化
* Construct: 1
* Destruct: 1
*/