IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 一文搞懂C++临时对象优化 附详细样例 -> 正文阅读

[C++知识库]一文搞懂C++临时对象优化 附详细样例

引入

C语言和C++在程序执行中,都是通过调用一系列的函数来实现的。并且,很多时候,编译器会帮助我们做一系列的事情,比如(在编译类的成员方法的时候,编译器默认添加 this 指针,以此来确定是哪一个对象调用了该成员方法)。得益于编译器或者说系统帮助我们做的一系列事情,我们可以更加方便地使用C++。但是凡事有利必有弊,因为系统有时候会自己调用一系列的函数,从另一个角度来说,也一定程度上降低了效率。
而我们想要提高C++的执行效率,就需要了解程序(主要是对象)使用过程中都调用了哪些方法。

测试环境

VS2019 x86环境下,编译器会影响最终结果的,如下面那个例子,VS2019 x86环境下是11个函数,而g++编译器则是9个函数,多余的优化下例有讲。

例子

#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;
	}
	int getdata()const { return ma; }
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;
}

对于上面的主函数,我们可以猜测一下一共调用了多少函数
答案如下:

Test(int)
Test(int)
Test(const Test&)
Test(int)
Test(const Test&)
~Test()
~Test()
operator=
~Test()
~Test()
~Test()

共调用了11个函数
我们可以来追踪一下

Test GetObject(Test t) //3.Test(const Test& t)
{
	int val = t.getdata();
	Test tmp(val);		//4.Test(int)
	return tmp;			//5.Test(const Test&) 因为tmp是局部对象,是出不了该函数这个花括
                        //号的,故需要临时传给外面main函数中的一个临时对象才能传出。(最
                        //起码vs2019编译器是这样做的)经测试g++编译器会对此进行优化,少了
                        //main函数的那个临时对象,因此总共就9个函数
}						//6.tmp析构 7.t的析构

int main()
{
	Test t1;	//1.Test(int)
	Test t2;	//2.Test(int)
	t2 = GetObject(t1);//8.Test& operator=(const Test& t) 9.用来传递的那个临时对象的析构

	return 0;
}					//10和11分别为 t1 t2 的析构

image.png
接下来可以进行讲解:

int main()
{
	Test t1;			//调用的是正常的构造函数
	Test t2(t1);		//Test(const Test&)
	Test t3 = t1;		//Test(const Test&)
	Test t4 = Test(20); //显式生成临时对象,但是与Test t1(20)没有区别
	t4 = t1;			//operator=
    t4=Test(30);		//Test(int)  operator=
	return 0;
}
Test(int)
Test(const Test&)
Test(const Test&)
Test(int)
operator=
Test(int)
operator=
~Test()
~Test()
~Test()
~Test()
~Test()

故对此可以总结:
c++编译器对于对象的构造的优化:用临时对象生成新对象的时候,临时对象就不产生了,直接用临时对象的值去构造新对象。
记住:只要是用临时对象去生成新对象的时候,临时对象都不会产生,不管是什么形式的临时对象。然而用临时对象去赋值已有对象时,临时对象便会生成。

故基于如上讲解我们可以对刚开始的例子进行优化(注释的地方即为改动)

Test GetObject(Test& t)
{
	int val = t.getdata();
	//Test tmp(val);
	return Test(val);
}

int main()
{
	Test t1;
	//Test t2;
	//t2 = GetObject(t1);
	Test t2 = GetObject(t1);

	return 0;
}
  1. 我们首先将函数的参数改为引用,对此节约了一个临时变量,函数-2
  2. 再取消tmp变量的构建,直接返回临时变量,同时把主函数中的t2的赋值操作改为初始化操作,触发优化条件:当用临时变量生成新变量的时候会进行优化,故省略掉了 tem变量 和 主函数中用来传递返回值的临时变量,函数-5(tmp 和 临时变量的构造和析构 t2的赋值)

故得到如下结果:

Test(int)
Test(int)
~Test()
~Test()

拓展

Test *p = &Test(20);		//p指向的是临时对象了,到下一行时临时对象会析构,造成悬垂指针
const Test &ref = Test(20);	//引用相当于给产生的临时对象赋予了别名,故临时对象不会销毁

结论:用指针指向临时对象是不安全的,用引用指向临时对象是安全的。

总结

于是我们总结出对象优化的原则:

  1. 不能返回局部的或者临时对象的指针或引用
  2. 函数参数传递过程中,对象优先按引用传递,不要按值传递
  3. 函数返回对象的时候,应该优先返回一个临时对象,而不要返回一个定义过的对象
  4. 接收返回值是对象的函数调用的时候,优先按初始化的方式接收,不要按赋值的方式接收
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:32:27  更:2022-07-03 10:35:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:43:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码