【C++】对象使用过程中背后调用的方法以及对象优化

对象使用过程中背后调用的方法

C++编译器对于对象构造的优化,用临时对象生成新对象的时候,临时对象不产生了,直接构建新对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXBNELoZ-1650776217562)(img/7C++%EF%BC%9A%E9%9D%A2%E7%BB%8F%E8%AE%B2%E8%A7%A3.img/image-20210228112011889.png)]
用临时对象赋值给已存在的对象的时候,要产生临时对象,再调用operator=
在这里插入图片描述
构造函数完成类型转换,(构造函数强转详细可查看博客:C++:构造函数强转、参数列表)

临时对象生存周期:所在的语句

而引用就是别名,相当于给这块内存又给了个名字,所以用引用引用临时对象,临时对象的生命周期就变成引用变量的生命周期了

所以用指针指向临时变量是不安全的,而用引用引用临时对象是安全的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3n6zAfk-1650776217564)(img/7C++%EF%BC%9A%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86.img/image-20210228114706992.png)]
程序运行,对象构造顺序以及背后调用总结

  • 先全局
  • 再进入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)

函数使用过程中背后调用的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jq0DI0Ot-1650776217565)(img/7C++%EF%BC%9A%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86.img/image-20210228124613372.png)]短短的代码调用了11个函数,可以优化

三条对象优化的规则

  • 1.函数参数传递过程中,对象优先按引用传递,不要按值传递

  • 2.函数返回对象的时候,应该优先返回一个临时对象,而不要返回一个定义过的对象
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lPXmAxA5-1650776217565)(img/7C++%EF%BC%9A%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86.img/image-20210228130829576.png)]

  • 接收返回值是对象的函数调用的时候,优先按初始化的方式接收,不要按赋值的方式接收

    • 初始化方式:Test t2 = GetObject(t1);

    • 赋值方式:Test t2;t2 = GetObject(t1);、

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNBQteGM-1650776217566)(img/7C++%EF%BC%9A%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86.img/image-20210228132210291.png)]
    在GetObject里面怎么知道t2在哪呢?看汇编就会发现当调用GetObject函数时,除了传入t1对象的地址,还把t2对象的地址也压入函数栈帧上了,所以GetObject可以取到t2的地址,就知道临时对象要直接构造在哪块内存上了

    分析的时候还是可以按正常的对象产生的方式去分析,但是遇到“临时对象拷贝构造同类型的新对象”时,就要注意编译器会进行优化,将临时对象直接构造在新对象的地方

经过优化,完成同样的功能,刚开始要调用11个函数,现在只需要调用4个函数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值