类和对象以及内存管理

news2024/11/13 14:35:32

对象拷贝时的编译器优化

  • 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少⼀些传参和传返回值的过程中可以省略的拷贝。
  • 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新⼀点的编译器对于连续⼀个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译器还会进行跨行跨表达式的合并优化。
#include<iostream>
using namespace std;

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

    A(const A& aa)
        :_a1(aa._a1)
    {
        cout << "A(const A& aa)" << endl;
    }

    A& operator=(const A& aa)
    {
        cout << "A& operator=(const A& aa)" << endl;
        if (this != &aa)
        {
            _a1 = aa._a1;
        }
        return *this;
    }

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

private:
    int _a1 = 1;
};

void f1(A aa)
{
}

A f2()
{
    A aa;
    return aa;
}

int main()
{
    //传值传参
    A aa1;
    f1(aa1);
    cout << endl;
    //隐式类型,连续构造+拷贝构造->优化为直接构造

    f1(1);
    //⼀个表达式中,连续构造+拷贝构造->优化为⼀个构造

    f1(A(2));
    cout << endl;
    cout << "***********************************************" << endl;

    //传值返回
    //返回时⼀个表达式中,连续拷贝构造+拷贝构造->优化⼀个拷贝构造(vs2019 debug)
    // ⼀些编译器会优化得更厉害,进行跨行合并优化,直接变为构造(vs2022 debug)

    f2();
    cout << endl;
    //返回时⼀个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造(vs2019 debug)
    //⼀些编译器会优化得更厉害,进行跨行合并优化,直接变为构造(vs2022 debug)

    A aa2 = f2();
    cout << endl;
    //⼀个表达式中,连续拷贝构造+赋值重载->无法优化

    aa1 = f2();
    cout << endl;
    return 0;
}

在这里插入图片描述

C/C++内存分布

在这里插入图片描述
说明:

  1. 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
  3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
  4. 数据段–存储全局数据和静态数据。
  5. 代码段–可执行的代码/只读常量。

由以上知识分析下列变量的位置:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
	static int staticVar = 1;
	int localVar = 1;
	int num1[10] = { 1, 2, 3, 4 };
	char char2[] = "abcd";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}

选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____
staticGlobalVar在哪里?____
staticVar在哪里?____
localVar在哪里?____
num1 在哪里?____

首先可以清楚的看出globalVarstaticGlobalVar为全局变量,因此存入数据段中;staticVarstatic修饰,生命周期发生变化,成为全局变量,因此也存入数据段中;localVar为局部变量,num1为局部数组,因此都在栈中。因此上述的答案为CCCAA

char2在哪里?____
*char2在哪里?___
pChar3在哪里?____
*pChar3在哪里?____
ptr1在哪里?____
*ptr1在哪里?____

char2num1相同都为局部数组,因此存入栈中;因为char2的数据在栈中,因此*char2也在栈中;pChar3为常量指针,存入栈中;因为*pChar3的数据为常量,因此存入代码段中;ptr1为地址,因此在栈中;由于ptr1是动态开辟的,因此 *ptr1在堆中。因此上述答案为AAADAB

C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理。

new/delete操作内置类型

void Test()
{
	// 动态申请一个int类型的空间
	int* ptr4 = new int;
	// 动态申请一个int类型的空间并初始化为10
	int* ptr5 = new int(10);
	// 动态申请10个int类型的空间
	int* ptr6 = new int[10];
	delete ptr4;
	delete ptr5;
	delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用newdelete操作符,申请和释放连续的空间,使用new[]delete[],注意匹配起来使用。

new和delete操作自定义类型

#include<iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	// new/delete 和 malloc/free最大区别是 new/delete对于
	// 自定义类型除了开空间还会调用构造函数和析构函数
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(1);

	free(p1);
	delete p2;
	// 内置类型是几乎是一样的
	int* p3 = (int*)malloc(sizeof(int)); 
	int* p4 = new int;
	free(p3);
	delete p4;

	A* p5 = (A*)malloc(sizeof(A) * 10);
	A* p6 = new A[10];
	free(p5);
	delete[] p6;

	return 0;
}

newmallocdeletefree的最大区别:在申请自定义类型的空间时,new会调用构造函数delete会调用析构函数,而mallocfree不会。

operator new与operator delete函数

newdelete是用户进行动态内存申请释放的操作符,operator newoperator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

//operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;
//申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,
//则继续申请,否则抛异常
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}

//operator delete: 该函数最终是通过free来释放空间的
void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK);  //block other threads 
	__TRY
		//get a pointer to memory block header 
		pHead = pHdr(pUserData);
		//verify block type
		_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
		_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK);  //release other threads
	__END_TRY_FINALLY
		return;
}

//free的实现
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

new和delete的实现原理

内置类型

如果申请的是内置类型的空间,newmallocdeletefree基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间new[]delete[]申请的是连续空间,而且new申请空间失败时会抛异常malloc会返回NULL

自定义类型

  • new的原理
    1. 调用operator new函数申请空间
    2. 在申请的空间上执行构造函数,完成对象的构造
  • delete的原理
    1. 在空间上执行析构函数,完成对象中资源的清理工作
    2. 调用operator delete函数释放对象的空间
  • new T[]的原理
    1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
    2. 在申请的空间上执行N次构造函数
  • delete[]的原理
    1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
    2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电池信息 v5.29.11 高级版,智能优化充电,最多可延长50%电池寿命

Charging Master 是一款非常实用的安卓 APP&#xff0c;专注于为您的手机充电提供最佳体验。借助其智能优化功能&#xff0c;Charging Master 能够最大程度地延长电池寿命&#xff0c;最多可达 50% 的节省。此外&#xff0c;该应用还提供了一系列功能&#xff0c;助您更好地管理…

提升团队效率的9款免费办公工具评测

本文主要介绍了以下9款协同办公软件&#xff1a;1.Worktile&#xff1b;2.PingCode&#xff1b;3.石墨文档&#xff1b;4.Teambition&#xff1b;5.蓝湖&#xff1b;6.工作宝&#xff1b;7.飞书&#xff1b;8.Asana&#xff1b;9.ClickUp。 在现代职场中&#xff0c;团队协作已…

GD - GD32350R_EVAL - PWM实验和验证1

文章目录 GD - GD32350R_EVAL - PWM实验和验证1概述笔记实验设计实验环境GD32350R_EVAL 的硬件连接修改程序配置 - 只产生PWM波&#xff0c;不要CMP清除波形TIMER0时钟设置TIMER0的PWM设置参数设置main()中PWM波形的开启代码示波器测量结果如果要产生4KHZ的PWM需要设置怎样的参…

在centos系统中kill掉指定进程

如上图&#xff0c;我想kill掉 python3 func_tg_1_vps.py这个进程&#xff08;而不kill掉python3 func_tg_2_vps.py&#xff09;。 解决方法&#xff1a; 第一步&#xff1a;首先使用ps -ef | grep python3命令&#xff0c;查出所有包含python3的命令 拿其中一条讲解 root …

开放式耳机漏音有多大?开放式耳机是否值得购买?

开放式耳机确实存在漏音的问题&#xff0c;这是因为其设计原理决定的。开放式耳机不像封闭式耳机那样完全封闭耳道&#xff0c;因此声音会向外散播&#xff0c;导致漏音。不过&#xff0c;随着技术的发展&#xff0c;许多耳机制造商已经开始着手解决这个问题&#xff0c;通过改…

Git之2.0版本重要特性及用法实例(五十六)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者. 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列…

VScode 使用记录

插件 1、代码提示插件&#xff1a;Codeium 安装说明&#xff1a;Codeium&#xff1a;强大且免费的AI智能编程助手 - Su的技术博客 (verysu.com) 用google账号登陆&#xff0c;跳转按照官网给的三个步骤来 step1&#xff1a;复制token&#xff1b; step2&#xff1a;在文件页…

中秋佳节,南卡Runner Pro5骨传导耳机让团圆更圆满!

中秋节&#xff0c;这个承载着温馨与团圆的节日&#xff0c;是向亲朋好友表达深情厚意的绝佳时刻。在这样一个特别的日子里&#xff0c;挑选一份既实用又充满科技感的礼物&#xff0c;无疑能够给人们带来惊喜与感动。南卡Runner Pro5骨传导耳机&#xff0c;凭借其创新的设计和卓…

绿色消费新动力:‘众店‘模式引领数字经济下的零售创新

在数字浪潮的推动下&#xff0c;传统零售业正经历着前所未有的转型。绿色消费积分系统&#xff0c;在这一变革中崭露头角&#xff0c;成为新兴消费平台的佼佼者。 一、"众店"平台的快速崛起 仅用两年时间&#xff0c;"众店"平台就实现了巨大的飞跃&#x…

代码随想录算法训练营day58:图论08:拓扑排序精讲;dijkstra(朴素版)精讲

拓扑排序精讲 卡码网&#xff1a;117. 软件构建(opens new window) 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依…

4_PMSM基于s函数的仿真建模_1

为了检验电机仿真模型的正确性&#xff0c;&#xff0c;以基于s函数方法搭建的数学模型为例&#xff0c;搭建如图的三相所示的简单三相PMSM矢量控制系统&#xff0c;此模型忽略了PWM逆变器的影响。另外&#xff0c;感兴趣的同志可以对基于Simulink方法搭建的仿真模型进行验证。…

二叉树详解(2)

文章目录 4. 二叉树链式结构的实现5. 二叉树基础oj练习 4. 二叉树链式结构的实现 首先&#xff0c;我们先要了解一下二叉树的遍历顺序有哪些&#xff1a; 通过了解二叉树的遍历顺序&#xff0c;我们不难看出要实现二叉树的遍历需要用到递归&#xff0c;而使用递归我们就要思…

基于STM32开发的智能电力监控与管理系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化电流电压数据采集与处理能耗计算与负载管理OLED显示与状态提示Wi-Fi通信与远程监控应用场景 工业设施的电力监控与优化智能家居中的电力管理与节能常见问题及解决方案 常见问题解决…

【C++ 面试 - STL】每日 3 题(二)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

Code Practice Journal | Day58_Graph08 Topological Sorting

1. 概念 在一个有向无环图(DAG)中&#xff0c;根据节点的依赖关系&#xff0c;对所有的节点进行线性排序的算法 拓扑排序的结果不一定是唯一的 2. 实现 2.1 BFS&#xff08;卡恩算法&#xff09; 1、步骤 2、代码实现 以KamaCoder 117.软体构建 题目&#xff1a;117. 软件…

Stable Diffusion绘画 | 插件-宽高比调整助手:让计算器毕业

在调整图片宽高时&#xff0c;如果每次都需要用计算器根据比例算好&#xff0c;再手工输入&#xff0c;非常影响效率。 推荐使用以下的插件&#xff0c;来实现高效准确地调整图片宽高比例。 Aspect Ratio Helper 安装地址&#xff1a;https://github.com/thomasasfk/sd-webui…

80、k8s概念及组件介绍

一、k8s kubernetes:k8s----希腊语&#xff0c;舵手&#xff0c;飞行员 1.1、k8s作用&#xff1a; ​ 用于自动部署&#xff0c;扩展&#xff0c;管理容器化部署的应用程序。开源&#xff08;半开源。&#xff09; ​ k8s的底层语言是由go语言。 ​ k8s理解成负责自动化运…

Jetson Orin Nano GPIO 舵机

jetson orin nano 40针引脚扩展接头&#xff1a; 图源 Jetson Orin Nano Developer Kit User Guide - | NVIDIA Developer 引脚配置 使用jetson-io tool配置引脚&#xff1a; sudo /opt/nvidia/jetson-io/jetson-io.py 选择“Configure Jetson 40pin Header”: "Confi…

啥是纳米微纤维?咋制作?有啥用?

大家好&#xff0c;今天我们来聊聊纳米/微纤维——《Tailoring micro/nano-fibers for biomedical applications》发表于《Bioactive Materials》。这些纤维近年来备受关注&#xff0c;因为它们具有独特的功能和性质&#xff0c;在生物医学等领域有广泛应用。它们可以通过多种技…

滴滴出行:分布式数据库的架构演进之路|OceanBase案例

本文作者&#xff1a;吴其朋&#xff0c;滴滴分布式存储运维负责人 滴滴出行&#xff0c;作为一个集网约车、出租车、顺风车、代驾等多种出行方式于一体的综合性出行服务平台&#xff0c;其用户遍布全球&#xff0c;总数已突破6.5亿。面对如此多样化的出行需求及庞大的用户群体…