前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优化对象变高效

优化对象变高效

作者头像
无敌清风蓝
发布2024-06-04 19:56:38
640
发布2024-06-04 19:56:38
举报
文章被收录于专栏:无敌清风蓝无敌清风蓝

引言

函数对象,以及其构造函数等,在C++中经常用,所以这篇文章就分析一下其中的调用以及如何优化

函数在使用过程调用了哪些方法

代码语言:javascript
复制
#include<iostream>
using namespace std;

class Test {
public:
	Test(int a = 10) : ma(a)
	{
		cout << "Test(int)" << endl;
	}
	~Test()
	{
		cout << "~Test()" << endl;
	}
	Test(const Test& t) :ma(t.ma)
	{
		cout << "Test(const Test&)" << endl;
	}
	Test& operator=(const Test& t)
	{
		cout << "operator=" << endl;
		ma = t.ma;
		return *this;
	}
private:
	int ma;
};

int main()
{
	Test t1;
	Test t2(t1);
	Test t3 = t1;

    // Test(20)是显式生成临时对象,生存周期为所在的语句
    /*
    C++编译器对于对象构造的优化:用临时对象生成新对象时,临时对象就不产生了,直接构造新对象就行
    */
	Test t4 = Test(20);// Test t4(20) 没有任何区别
	cout << "------------" << endl;

	t4 = t2; // t4.operator = (const Test & t);
	// 显式生成临时对象
    /*
    因为这时候t4已经有了,所以再用临时对象的话,临时对象就要产生
    */
	t4 = Test(30);
	t4 = (Test)30;
	// 隐式生成临时对象
	t4 = 30; // Test(30) int->Test(int)

	cout << "------------" << endl;

	
	return 0;
}

运行结果为:

t4 = Test(30);是先临时生成一个对象所以调用了Test(int),这个临时对象再赋值给t4,所以调用了operator=,临时对象再析构,所以是~Test()

下面这三行代码,都是

Test(int)

operator=

~Test()

代码语言:javascript
复制
// 显式生成临时对象
t4 = Test(30);
t4 = (Test)30;
// 隐式生成临时对象
t4 = 30;

只不过前两个是显式,因为指明了Test,只不过从Test里面找int,最后一个是隐式,推断t4的类Test,再通过30这个int,找Test里面的int

前两个没有任何区别

这时再在上面的代码最后再加上这样的代码

代码语言:javascript
复制
p指向的是一个已经析构的临时对象
Test *p = &Test(40);
const Test &ref = Test(50);

此时输出会显示为

代码语言:javascript
复制
Test(int)  临时对象产生
~Test()		临时对象析构,当Test *p = &Test(40);这一句执行后,就被析构,所以此时指针已经无效了,因为临时对象已经被析构
Test(int)	引用的临时对象
~Test()	当main函数结束时,被析构

临时对象是没有名字的,所以过了这一句的生命周期,用指针指的话,就为空了

但是引用相当于别名,是把这块内存安了个名字,在这里,只有当引用对象什么时候出作用域,它才被析构

所以用指针指向临时对象是不安全的

再看两个

代码语言:javascript
复制
Test *p1 = new Test(10); // Test(int) 此时不是临时对象因为用的new,在堆上分配,而上面的是在栈上
Test *p1 = new Test[2]; // Test(int) Test(int)两次构造
delete p1; // ~Test()
delete []p2;// ~Test()  ~Test()

函数调用过程中,对象背后调用的方法太多

代码语言:javascript
复制
// 正确写法
Test GetObject(Test t)
{
	int val = t.getData();
	Test tmp(val);
	return tmp;
}

// 错误写法
Test* GetObject(Test t)
{
	int val = t.getData();
	Test tmp(val);
	return &tmp;
}
/*
因为这里的tmp是在函数里的局部对象,所以就算tmp传递一个指针,我们通过返回值知道地址后,但是这个函数运行结束后,这个内存就没了,所以这个对象的内存也就没了,那你知道了他的地址也没用了,所以不能返回局部的或者临时对象的指针或者引用
*/

// 正确写法
Test* GetObject(Test t)
{
	int val = t.getData();
	static Test tmp(val);
	return &tmp;
}
/*
这样就可以,因为static是一开始就分类的内存,他一直都在
*/

代码语言:javascript
复制
#include <iostream>
using namespace std;

Class Test
{
public:
    Test(int data = 10) :ma(data) //初始化ma的值
    {
        cout << "Test(int)" << endl;
    }
    ~Test()
    {
        cout << "~Test()"<< endl;
    }
    Test(const Test& t) :ma(t.ma)
    {
        cout << "Test(const Test&)" << endl;
    }
private:
    int ma;
};

Test GetObject(Test t)
{
	int val = t.getData();
	Test tmp(val);
	return tmp;
}

int main()
{
    Test t1;
    Test t2;
    t2 = GetObject(t1);
    return 0;
}

这三行代码,其实调用了11个函数

三条对象优化的规则

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

2.函数返回对象的过程中,应该优先返回一个临时对象,而不要返回一个定义过的对象

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

把上面的代码优化成这样

代码语言:javascript
复制
Test GetObject(Test &t) // 按引用传递,这样这里就少了一个构造
{
	int val = t.getData();
	//Test tmp(val);
	//return tmp;
    return Test(val); // 返回临时对象,这样少了上面两行的构造
}

int main()
{
    Test t1;
    Test t2 = GetObject(t1); //按初始化的方式接受
    //t2 = GetObject(t1);
    return 0;
}

这是第二条优化

这是第三条:

优化后,函数调用从11个变成了4个

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023/05/27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 函数在使用过程调用了哪些方法
  • 三条对象优化的规则
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档