对象使用过程中背后调用的方法
C++编译器对于对象构造的优化,用临时对象生成新对象的时候,临时对象不产生了,直接构建新对象
用临时对象赋值给已存在的对象的时候,要产生临时对象,再调用operator=
构造函数完成类型转换,(构造函数强转详细可查看博客:C++:构造函数强转、参数列表)
临时对象生存周期:所在的语句
而引用就是别名,相当于给这块内存又给了个名字,所以用引用引用临时对象,临时对象的生命周期就变成引用变量的生命周期了
所以用指针指向临时变量是不安全的,而用引用引用临时对象是安全的
程序运行,对象构造顺序以及背后调用总结
- 先全局
- 再进入main
注意:
-
静态局部变量,内存分配是在程序运行之前就分配好的,因为有初值的静态局部变量存储在.data区,.data区的内存是事先就分配好的;但是静态局部变量的初始化(对象的构造)是在运行到它的时候才初始化,.data区析构的时候是程序结束(main结束)的时候析构
-
new比malloc多的:new不仅分配内存,还构建对象;delete比free多的:delete不仅释放内存,释放之前先调用析构函数
-
析构顺序:p1,p2,p4引用的变量,t3,t2,t4,t5,t1 (注意:t1,t5,t4是在.data区,构造的时候是154,析构就是451)
对象底层调用代码示例:(注释是构造顺序与底层调用的方法)
class Test
{
public:
// 带默认值,这三种形式都可以构造:Test() Test(10) Test(10, 10)
Test(int a = 5, int b = 5) :ma(a), mb(b) { cout << "Test(int, int)" << endl;}
~Test() { cout << "~Test()" << endl; }
Test(const Test &src) :ma(src.ma), mb(src.mb)
{
cout << "Test(const Test&)" << endl;
}
void operator=(const Test &src)
{
ma = src.ma;
mb = src.mb;
cout << "operator=" << endl;
}
private:
int ma;
int mb;
};
Test t1(10, 10); // 1.Test(int, int)
int main()
{
Test t2(20, 20); // 3.Test(int, int)
Test t3 = t2; // 4.Test(const Test&)
static Test t4 = Test(30, 30); // 5.Test(int, int),等价于static Test t4(30, 30);
t2 = Test(40, 40); // 6.Test(int, int) operator= ~Test()
t2 = (Test)(50, 50); // 7.Test(int,int) operator= ~Test(),逗号表达式(50, 50) = (Test)50; Test(int)
t2 = 60; //Test(int) 8.Test(int,int) operator= ~Test()
Test *p1 = new Test(70, 70); // 9. Test(int,int)
Test *p2 = new Test[2]; // 10. Test(int,int) Test(int,int)
Test *p3 = &Test(80, 80); // 11. Test(int,int) ~Test()
const Test &p4 = Test(90, 90); // 12. Test(int,int)、
delete p1; // 13.~Test()
delete[]p2; // 14. ~Test() ~Test()
}
Test t5(100, 100); // 2.Test(int, int)
函数使用过程中背后调用的方法
短短的代码调用了11个函数,可以优化
三条对象优化的规则
-
1.函数参数传递过程中,对象优先按引用传递,不要按值传递
-
2.函数返回对象的时候,应该优先返回一个临时对象,而不要返回一个定义过的对象
-
接收返回值是对象的函数调用的时候,优先按初始化的方式接收,不要按赋值的方式接收
-
初始化方式:Test t2 = GetObject(t1);
-
赋值方式:Test t2;t2 = GetObject(t1);、
在GetObject里面怎么知道t2在哪呢?看汇编就会发现当调用GetObject函数时,除了传入t1对象的地址,还把t2对象的地址也压入函数栈帧上了,所以GetObject可以取到t2的地址,就知道临时对象要直接构造在哪块内存上了分析的时候还是可以按正常的对象产生的方式去分析,但是遇到“临时对象拷贝构造同类型的新对象”时,就要注意编译器会进行优化,将临时对象直接构造在新对象的地方
-
经过优化,完成同样的功能,刚开始要调用11个函数,现在只需要调用4个函数