C++相关概念和易错语法(8)(匿名对象、构造+拷贝构造优化、构造析构顺序)

1.匿名对象

当我们实例化对象后,有的对象可能只使用一次,之后就没用了。这个时候我们往往要主动去析构它,否则会占着浪费空间。但是如果遇到大量的这种情况,我们并不想每次都去创建对象、调用、析构,这样会写出很多重复无聊的代码,为了精简,可以考虑使用匿名对象

下面是它使用的一个实例:


#include <iostream>
using namespace std;

class A
{
public:
	A(int a = 0, int b = 0)
		:_a(a)
		,_b(b)
	{
		cout << "A(int a = 0, int b = 0)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	void Fun()
	{
		cout << "调用函数" << endl;
	}
private:
	int _a;
	int _b;
};

int main()
{
	cout << "在这之后构造\n" << endl;

	A().Fun();

	cout << "\n在这之前析构" << endl;

	return 0;
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

运行的结果是

我们可以发现,匿名对象的生命周期就在那一行,在调用之后就会立马销毁。这会让我们在某些情况下代码量大大减少,看上去也很直观。

注意书写格式:

2.构造函数、拷贝构造、析构函数的优化

对于任何表达式,它都会有一个返回值,这个返回值是一个临时常变量,如果有变量接收就赋值给它,如果没有就抛弃。对于类和对象的相关操作理论上也应如此。但和内置类型不同,对象每次进行一次复制需要的开销都很大,对性能影响很大,所以编译器会做出优化,简化现有逻辑,提高效率。

下面是一些常见的在VS2022上Debug下的优化:

对于优化问题,我们常常讨论的是构造次数,因为析构和构造成对出现。

主要的优化类型是:构造+拷贝构造->构造

a.隐式类型转换


#include <iostream>
using namespace std;

class A
{

public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	A(const A& a)
		: _a(a._a)
	{
		cout << "A(A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

private:
	int _a;
};

int main()
{
	A a = 1;

	return 0;
}

对于A a = 1,一般逻辑是先将1作为形参调用单参数的A的构造函数得到临时常对象tmp,再采用拷贝构造给a初始化。

但是优化之后就不会生成这个临时变量了。编译器会直接将1作为参数调用对象a对应的构造函数进行初始化。这样的话就少了一次拷贝。

b.隐式类型转换+调用函数


#include <iostream>
using namespace std;

class A
{

public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	A(const A& a)
		: _a(a._a)
	{
		cout << "A(A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	static	void Fun(A a)
	{
		cout << "Fun(A a)" << endl;
	}

private:
	int _a;
};

int main()
{
	A::Fun(1);

	return 0;
}

在这段代码中,1应该先调用构造生成临时对象,再将这个对象拷贝构造给形参a。

但是在这里,我们就直接将1作为参数去调用a的对应的构造函数,就不会去生成那个临时变量了。

c.当匿名对象作为实参


#include <iostream>
using namespace std;

class A
{

public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	A(const A& a)
		: _a(a._a)
	{
		cout << "A(A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	static	void Fun(A a)
	{
		cout << "Fun(A a)" << endl;
	}

private:
	int _a;
};

int main()
{
	A::Fun(A(1));

	return 0;
}

这里,本来的逻辑是1先去调用匿名对象的构造函数,完成匿名对象的初始化;然后匿名对象再去调用形参a的拷贝构造,完成a的初始化。

但是我们知道匿名对象是即用即扔的,它和临时对象没什么区别,都只在当前行有作用,因此这里依然是跳过构造匿名对象,直接将1作为参数去调用形参的构造函数。

借助这个优化,我们可以减少代码量


int main()
{
	A::Fun(A(1));//两种写法相同
	A::Fun(1);

	return 0;
}

一般来说采用后者的写法,毕竟要写的代码量更小,而且提高可读性。

d.函数返回值是自定义类型


#include <iostream>
using namespace std;

class A
{

public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	A(const A& a)
		: _a(a._a)
	{
		cout << "A(A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	static	A Fun()
	{
		cout << "Fun(A a)" << endl;
		return A(2);
	}

private:
	int _a;
};

int main()
{
	A ret = A::Fun();

	return 0;
}

在调用完函数后,函数应该返回值并赋值。这里的逻辑应该是先将2作为参数去调用匿名对象的构造函数,然后将这个匿名对象拷贝构造给ret,使其初始化。

在优化后,我们直接将2作为参数去调用ret的构造函数。

但是,有的情况并不会优化,主要是看构造函数和拷贝构造有没有在一行代码中连续调用。



#include <iostream>
using namespace std;

class A
{

public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	A(const A& a)
		: _a(a._a)
	{
		cout << "A(A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	A& operator= (const A& tmp)
	{
		cout << "A& operator= (const A& tmp)" << endl;
		_a = tmp._a;
		return *this;
	}

	static	A Fun()
	{
		cout << "Fun(A a)" << endl;
		return A(2);
	}

private:
	int _a;
};

int main()
{
	A ret;

	ret = A::Fun();

	return 0;
}

很明显,这里ret的初始化在调用函数前一行,会直接调用它的构造函数。之后进入函数,返回值需要再调用一次匿名对象的构造函数 ,之后调用的是赋值重载运算符。

在这里没有使用构造+拷贝构造,所以没有可优化的地方,一切执行逻辑和我们的推导逻辑一致。

3.构造和析构的顺序

(1)全局对象最先构造,在程序开始时就按顺序构造。

(2)局部static对象在第一次调用才构造,第二次就不构造了。

(3)普通的局部对象按顺序构造

(4)除了static修饰的局部对象以外,所有对象(局部、全局)先构造的后析构。

(5)static修饰的局部对象因为生命周期发生了改变,在所有局部对象都析构之后,在全局对象析构之前按“栈”的规则析构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/563530.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软考 系统架构设计师系列知识点之大数据设计理论与实践(15)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之大数据设计理论与实践&#xff08;14&#xff09; 所属章节&#xff1a; 第19章. 大数据架构设计理论与实践 第4节 Kappa架构 19.4.5 常见Kappa架构变型 1. Kappa架构 Kappa是Uber提出的流式数据处理架构&#xff0…

传统与创新的交响:『线上求签祈福』游戏案例赏析

Part1. 设计背景 在当代社会&#xff0c;寺庙文化正经历一场复兴&#xff0c;尤其受到年轻一代的热烈欢迎。无论是在传统的节假日还是平日里&#xff0c;寺庙总是吸引着众多年轻人前来&#xff0c;他们怀着虔诚的心祈求平安健康或财富好运。在面对生活中难以抉择或无法掌控的情…

JAVA-服务器搭建-创建web后端项目

首先打开IDEA 点击新建项目 写好名称-模板选择 Web应用程序 -语言选择 Java 构建系统选择 Maven 然后点击下一步 选择版本-选择依赖项 Web Profile 点击创建 点击当前文件-选择编辑配置 选择左上角的加号-选择Tomcat服务器-选择本地 点击配置-选择到Tomcat目录-点击确定 起个…

创建会计凭证:BAPI_ACC_DOCUMENT_POST 增强字段

创建会计凭证&#xff1a;BAPI_ACC_DOCUMENT_POST 增强字段 在ABAP程序中使用BAPI_ACC_DOCUMENT_POST的时候&#xff0c;如果有些字段在Tables参数中没有&#xff0c;比如&#xff0c;现在大家都用Reason code来作为现金流量表的表现方案。但是在BAPI_ACC_DOCUMENT_POST的acco…

Java新特性(jdk8)

第一章-lambda表达式 1.函数式编程思想和Lambda表达式定义格式 1.面向对象思想: 强调的是找对象,帮我们去做事儿 比如:去北京 -> 强调的是怎么去,火车,高铁,飞机,汽车,自行车,腿儿 2.jdk8开始有了一个新的思想:函数式编程思想: 强调的是结…

FreeRTOS之任务挂起和恢复

1.本文介绍FreeRTOS的任务挂起和恢复函数。任务删除后将不再存在&#xff0c;不能恢复&#xff0c;而任务挂起是暂停任务&#xff0c;可以通过调用函数进行恢复。FreeRTOS任务挂起和恢复的主要步骤如下&#xff1a; &#xff08;1&#xff09;将相关的宏定义设置为1&#xff1…

OPAM模型(细粒度图像分类)

OPAM模型&#xff08;细粒度图像分类&#xff09; 摘要Abstract1. OPAM1.1 文献摘要1.2 细粒度图像分类1.3 研究背景1.4 OPAM模型创新点1.5 OPAM模型1.5.1 补丁过滤1.5.2 显着性提取1.5.3 细粒度区域级注意模型对象-空间约束方法&#xff08;Object spatial constraint&#xf…

钟薛高创始人称卖红薯也把债还上:网友,您可千万别……

网红雪糕品牌钟薛高&#xff0c;是真的网红属性强到让所有消费品牌羡慕。 纵使跌落神坛、纵使站在「破产」边缘&#xff0c;依然话题感满满&#xff0c;隔段时间&#xff0c;总能上一个热搜。 比如欠薪上热搜、产品降价上热搜、甚至官网微博微信停更&#xff0c;也得上个热搜&…

MLLM | InternLM-XComposer2-4KHD: 支持336 像素到 4K 高清的分辨率的大视觉语言模型

上海AI Lab&#xff0c;香港中文大学等 论文标题:InternLM-XComposer2-4KHD: A Pioneering Large Vision-Language Model Handling Resolutions from 336 Pixels to 4K HD 论文地址:https://arxiv.org/abs/2404.06512 Code and models are publicly available at https://gi…

.net core webapi 添加日志管理看板LogDashboard

.net core webapi 添加日志管理看板LogDashboard 添加权限管理&#xff1a; 我们用的是Nlog文件来配置 <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi"http:/…

网络基础-TCP/IP和OSI协议模型

一、OSI和TCP/IP模型 二、OSI七层模型 三、TCP/IP模型 参考&#xff1a;https://www.cnblogs.com/f-ck-need-u/p/7623252.html

Scanpy(1)数据结构和样本过滤

注&#xff1a;主要讲述scanpy处理数据的结构、数据过滤&#xff08;生信领域&#xff09;和数据预处理&#xff08;和机器学习类似&#xff0c;但是又有不同。&#xff09; 1. Scanpy简介与安装 Scanpy 是一个可扩展的工具包&#xff0c;用于分析与 AnnData&#xff08;一种…

螺纹滑牙的原因有哪些——SunTorque智能扭矩系统

螺纹滑牙的原因&#xff0c;通常是由于在旋紧或旋松过程中&#xff0c;螺纹副之间的摩擦力不足以维持所需的预紧力或工作载荷&#xff0c;导致螺纹副的相对位置发生变化。这种现象可能由多种因素引起&#xff0c;包括材料选择不当、设计不合理、制造工艺缺陷、环境因素以及使用…

欧科云链:香港虚拟资产OTC合规在即,技术监管成市场规范关键

4月12日香港OTC发牌制度公众咨询结束后&#xff0c;欧科云链研究院在星岛日报发表专栏文章&#xff0c;分享对香港OTC市场的调研情况&#xff0c;并提出“技术监管是香港OTC及Web3生态走向规范的关键”。欧科云链研究院认为&#xff0c;随着OTC监管及虚拟资产现货ETF等事件向前…

DC30V36V60V100V转9V、12V/1.5A方案 车灯驱动芯片IC H5028L ,高性价比,皮实耐抗

DC24V、30V、36V、60V、100V转9V、12V/1.5A方案&#xff0c;以及车灯驱动芯片IC&#xff0c;这通常涉及到电源转换和驱动电路的设计。这些方案的目标是将一个较高的直流电压&#xff08;如24V、30V、36V、60V或100V&#xff09;转换为较低但稳定的直流电压&#xff08;如9V或12…

Leetcode 第 394 场周赛

Leetcode 第 394 场周赛 1. [统计特殊字母的数量 I](https://leetcode.cn/problems/count-the-number-of-special-characters-i/)2. [统计特殊字母的数量 II](https://leetcode.cn/problems/count-the-number-of-special-characters-ii/)3. [使矩阵满足条件的最少操作次数](htt…

前端工程化02-复习jQuery当中的插件开发

2、jQuery插件开发 在我们开发的时候、有时候jQuery提供的方法并不能满足我们的需求&#xff0c;如果我们想给jQuery扩展一些其他的方法&#xff0c;那这种情况下&#xff0c;可能会需要写一个插件 jQurey官网&#xff1a;jquery.com 例如一些、图片懒加载插件、滚动的插件、…

BUUCTF-MISC-04大白

题目&#xff1a;让图片全面显示宽高 更改高宽一致 发现大白没有完全显示&#xff0c;优先考虑到图片高度隐写,猜测是FLAG隐藏在少掉的部分里&#xff0c;所以需要修改图片的高度与宽一致 我们借助010工具完成操作 根据内容可以看到高和宽不一样&#xff0c;这时候&#xff0…

图像处理基础知识

图像处理基础知识 图像 1、模拟图像 模拟图像&#xff0c;又称连续图像&#xff0c;是指在二维坐标系中连续变化的图像&#xff0c;即图像的像点是无限稠密的&#xff0c;同时具有灰度值&#xff08;即图像从暗到亮的变化值&#xff09;。 2、数字图像 数字图像&#xff0…

Jenkins CI/CD 持续集成专题一 Jenkins的安装和配置

一 jenkins 官方教程 安装Jenkins 二 安装 2.1 安装方式一 通过安装包的package方式安装 第一步下载链接&#xff1a; Download the latest package 第二步操作方式&#xff1a;打开包装并按照说明操作 2.2 安装方式二 brew安装 第一 安装最新版本jenkins brew install …