C++基础知识七

news2024/11/14 20:37:22

1.对象拷贝时编译器优化

 现代编译器为了尽快提高程序的效率,不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝

例子:

先调用f()函数,则应该先触发构造函数初始化a,return a时先拷贝a到应该临时变量上,会触发拷贝构造,然后a再触发析构函数,临时变量在当行结束后就销毁了,但是运行结果只有构造函数和析构函数,所以可以知道编译器进行了优化操作。

在C++中,临时变量(或临时对象)的生命周期有一些关键的规则:

1.函数返回值:
临时对象的生命周期通常会延续到包含它的表达式的结束。特别是当临时对象作为函数的返回值时,它的生命周期会被延续到初始化它的对象的构造过程结束。例如:

   A getObject() {
       return A();  // 临时对象 A() 的生命周期延续到 getObject() 返回值初始化
   }


2.赋值和初始化:
在赋值或初始化过程中,临时对象的生命周期通常会延续到赋值或初始化操作完成。例如:

   A a = A(1);  // 临时对象 A(1) 的生命周期延续到 a 的初始化完成


3.常量表达式:
临时对象的生命周期可以延续到其使用的上下文。例如,在常量表达式中,临时对象的生命周期会延续到该表达式的结束。
4.绑定到const引用:
如果临时对象被绑定到const引用,则临时对象的生命周期会被延续到绑定到该引用的对象的生命周期结束。例如:

   const A& ref = A();  // 临时对象 A() 的生命周期延续到 ref 的生命周期结束


5.无 const 引用绑定:
如果临时对象没有被绑定到const引用,临时对象的生命周期通常不会延续,可能会导致未定义行为。因此,直接使用临时对象创建非const引用是不安全的。

总结来说,临时对象的生命周期通常会被延续到当前作用域的结束,尤其是当它被绑定到const引用或用于初始化其他对象时。理解这些规则对于正确管理对象的生命周期和避免未定义行为非常重要。

#include<iostream>
#include<assert.h>
#include <algorithm>
using namespace std;


class A
{
public:
	A(int a1=1, int a2=1)
	:_a1(a1)
	,_a2(a2)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& d)
	{
		cout << "A(const A&d)" << endl;
	}
	A& operator=(const A& d)
	{
		cout << "A& operator=(const A& d)" << endl;
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
	void Print()
	{
		cout << "A->Print->" << _a1 << endl;
	}
	A& operator++()
	{
		_a1 += 100;
		return *this;
	}
private:
	int _a1=0;
	int _a2=0;
};
A f()
{
	A a(1);
	return a;
}
int main()
{
	f();
	return 0;
}

 

二:

首先调用函数会构造aa,然后是重载函数,返回是返回临时变量则需要拷贝构造然后析构aa,在拷贝给ret,而运行结果只有构造函数,重载函数和析构函数。

A f()
{
	A aa(2);
	++aa;
	return aa;
}
int main()
{
	A ret = f();
	return 0;
}

 

2.C++管理内存方式

C语言内存管理方式在C++中可以继续使用,但也有些麻烦,所以C++有自己的内存管理方式:通过new和delete操作进行动态内存管理。

2.1new/delete操作内置类型

int main()
{
	//动态申请一个int类型空间
	int* p1 = new int;
	//动态申请一个int类型空间并且初始化为10
	int* p2 = new int(10);
	//动态申请10个int类型空间
	int* p3 = new int[10];

	delete p1;
	delete p2;
	delete[] p3;
	return 0;
}

new和delete就是C的加强版malloc和free

申请和释放单个元素的空间,使用new和delete,申请和释放连续空间,使用new[]和delete[],匹配起来使用。

2.2new和delete操作自定义类型

	int* p3 = (int*)malloc(sizeof(int));
	int* p4 = new int;
	free(p3);
	delete p4;

对于内置来说这俩个几乎是没有区别的

	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(1,1);
	free(p1);
	delete p2;

而对于自定义类型new和delete除了会开空间和释放空间还会调用构造函数和析构函数 

 3.operator new与operator delete函数

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

malloc申请失败会返回NILL,而new申请失败则会抛出异常

4.new和delete实现原理

内置类型:

如果申请的是内置类型空间,new和mallco,delete和free基本相似

自定义类型:

new原理:

1.调用operator new函数申请空间

2.在申请的空间上执行构造函数,完成对象的构造

delete原理:

1.在空间上执行析构函数,完成对象资源的清理

2.调用operator delete函数释放对象空间

new T[N]的原理:

1.调用operator new[]函数,在operator new[]中调用operator new函数完成N个对象的空间申请

2.在申请的空间上执行N次构造函数

delete[]的原理:

1。在释放的对象空间上执行N次析构函数,完成对N个对象中资源的清理

2.调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

 

注意:若是不匹配来则会出问题

class A
{
public:
	A(int a1=1, int a2=1)
	:_a1(a1)
	,_a2(a2)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& d)
	{
		cout << "A(const A&d)" << endl;
	}
	A& operator=(const A& d)
	{
		cout << "A& operator=(const A& d)" << endl;
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
	void Print()
	{
		cout << "A->Print->" << _a2 << endl;
	}
	A& operator++()
	{
		_a2 += 100;
		cout << "A& operator++()" << endl;
		return *this;
	}
private:
	int _a1=0;
	int _a2=0;
};
A f()
{
	A aa(2);
	++aa;
	cout << "hhhh"<< endl;
	return aa;
}
class B
{
public:
	void Print()
	{
		cout << "h" << endl;
	}
private:
	int _a1 = 1;
	int _a2 = 1;
};
int main()
{
	A* p = new A[10];
	B* p1 = new B[10];
	delete p;
	delete p1;

	return 0;
}

 

因为在开辟10个类型A的空间时(此时有八十个字节),但是还会再开辟一个四个字节的空间去储存有多少个的数量,而delete p就是从四个字节后开始释放,但是在C中我们知道free要从头开始,所以会报错,只有delete[] p才会从头开始释放,而p1没问题是因为类B没有些析构函数,但B有析构函数时也会报错,没有析构则编译器认为B的数据都是内置直接释放就行。

 

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

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

相关文章

机器学习之监督学习(一)线性回归、多项式回归、算法优化[巨详细笔记]

机器学习之监督学习&#xff08;一&#xff09;线性回归、多项式回归、算法优化 1.监督学习定义2.监督学习分类2.1回归 regression2.2 分类 classification 3.线性回归 linear regression3.1 单特征线性回归模块一&#xff1a;梯度下降 3.2 多特征线性回归模块二&#xff1a;正…

CohereForAI更新企业级开源模型 c4ai-command-r-08-2024和c4ai-command-r-plus-08-2024

C4AI Command R 08-2024 是一个 350 亿参数高性能生成模型的研究版本。 Command R 08-2024 是一个大型语言模型&#xff0c;采用开放式权重&#xff0c;针对推理、总结和问题解答等各种用例进行了优化。 Command R 08-2024 具备多语言生成功能&#xff0c;曾在 23 种语言上进行…

nginx平滑升级与回滚

华子目录 升级实验环境准备测试内容准备实验要求实验步骤1.解压包2.检测1.26版本的环境3.make编译4.备份之前的nginx启动脚本5.将1.26中的nginx启动脚本覆盖掉1.24中的6.kill -USR2 旧主进程pid7.kill -WINCH 旧主进程pid 实验测试 回滚1.kill -HUP 旧主进程pid2.kill -WINCH 新…

【MySQL】索引性能分析工具详解——>为sql优化(select)做准备

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

机械学习—零基础学习日志(概率论总笔记1)

概率论的起源 在历史上有明确记载的最早研究随机性的数学家是帕斯卡和费马。帕斯卡就是最早发明机械计算机的那位数学家&#xff0c;他并不是赌徒&#xff0c;但是他有些赌徒朋友&#xff0c;那些人常常玩一种掷骰子游戏&#xff0c;游戏规则是由玩家连续掷4次骰子&#xff0c…

Java | Leetcode Java题解之第378题有序矩阵中第K小的元素

题目&#xff1a; 题解&#xff1a; class Solution {public int kthSmallest(int[][] matrix, int k) {int n matrix.length;int left matrix[0][0];int right matrix[n - 1][n - 1];while (left < right) {int mid left ((right - left) >> 1);if (check(matr…

Python酷库之旅-第三方库Pandas(113)

目录 一、用法精讲 496、pandas.DataFrame.kurtosis方法 496-1、语法 496-2、参数 496-3、功能 496-4、返回值 496-5、说明 496-6、用法 496-6-1、数据准备 496-6-2、代码示例 496-6-3、结果输出 497、pandas.DataFrame.max方法 497-1、语法 497-2、参数 497-3、…

如何从 SD 卡恢复已删除的文件:分步指南

在 SD 卡上查找已删除的文件可能是一项相当艰巨的任务&#xff0c;尤其是当您认为它们已经消失得无影无踪时。然而&#xff0c;希望还是有的&#xff01;现代技术提供了多种有效的方法来恢复这些文件&#xff0c;无论是照片、文档还是其他类型的数据。使用正确的工具和一点耐心…

【初出江湖】大白话解释集中式、分布式、微服务的区别?

目录标题 什么是集中式&#xff1f;什么是分布式&#xff1f;分布式系统的架构一般构成模块分布式的优点分布式的缺点什么是分布式集群&#xff1f; 什么是微服务&#xff1f;微服务和分布式系统有什么主要区别&#xff1f;微服务架构与分布式系统在开发过程中有何不同&#xf…

嵌入式:Arm v7-M指令集架构中的字节序(大小端)

相关阅读 嵌入式https://blog.csdn.net/weixin_45791458/category_12768532.html?spm1001.2014.3001.5482 本文来源于博主无意之中的一个发现&#xff0c;虽然之前就知道Cortex-M3默认为小端模式&#xff0c;但是偶然发现了一些出乎意料的情况。 首先来看看Arm v7-M指令集架构…

【MarkDown】表格的对齐方法

MarkDown中表格的对齐方法 说明格式化对齐举例 摘要&#xff1a; 1.本文介绍了MarkDown语法中&#xff0c;插入表格后&#xff0c;表格的对齐方法 2.在CSDN写博客时&#xff0c;要经常用的功能&#xff0c;务必掌握这个小技巧 说明 在Markdown中创建表格&#xff0c;基本结构由…

奇偶校验、crc循环冗余检验

数据链路层 链路 从一个结点到相邻结点的一段物理线路&#xff0c;而中间没有任何其他的交换点 数据链路 是指把实现通信协议的硬件和软件加到链路上 帧 在数据链路上传输的数据包&#xff0c;称之为帧 数据链路层是以帧为单位进行传输和处理数据的 数据链路层的三个重…

用Springboot(java程序)访问Salesforce RestAPI(通过JWT认证)

外部系统想访问Salesforce的数据,发Rest请求,必须需要Salesforce的AccessToken。那么为了得到这个AccessToken,Salesforce有几种方式可供选择。 一种就是用户名密码认证方式(之前的文章介绍过通过java代码访问Salesforce),一种就是JWT认证方式。当然还有其他方式,之后有…

利用Streamlit前端框架开发Stable Diffusion模型图像生成网页应用(下篇)

今天介绍亚马逊云科技推出的国际前沿人工智能模型平台Amazon Bedrock上的Stability Diffusion模型开发生成式AI图像生成应用&#xff01;本系列共有3篇&#xff0c;在上篇中我们学习了如何在亚马逊云科技控制台上体验该模型的每个特色功能&#xff0c;如文生图、图生图、图像修…

认知杂谈41

今天分享 有人说的一段争议性的话 I I 贫富根源在观念 I 你知道不&#xff1f;穷人穷啊&#xff0c;好多时候是因为他们自己还有家里好几代人呢&#xff0c;都陷在一种不对的想法里出不来&#xff0c;还觉得这样挺好&#xff0c;就一直这么过下去了。可富人的那些想法呢&am…

借老系统重构机会我写了个groovy规则引擎

公司老系统的重构计划早就有了&#xff0c;为了对Java硬编码的各种校验规则进行重构&#xff0c;特地参考了相关技术&#xff0c;最终选择了groovy进行了系统的学习&#xff0c;并编写了一个即插即用的轻量级规则引擎。 文章目录 项目背景技术选型groovy的性能groovy脚本执行线…

Scala之父Martin Odersky作序推荐的Scala速学版(第3版)出版

Scala 是一个很有吸引力的选择。 Scala 的语法简洁&#xff0c; 跟 Java 的“陈词滥调”比起来让人耳目一 新。它运行在 Java 虚拟机&#xff08;Java virtual machine &#xff0c;JVM&#xff09;上&#xff0c;提供对大量库和工具的访问。并 且&#xff0c;Scala 不仅仅瞄准…

设计模式之适配器模式:软件世界的桥梁建筑师

一、什么是适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff08;Structural Pattern&#xff09;&#xff0c;通过将类的接口转换为客户期望的另一个接口&#xff0c;适配器可以让不兼容的两个类一起协同工作。其核心思想是通过一个…

嵌入式全栈开发学习笔记---Linux系统编程(概述)

目录 入门级问题 为什么要学习Linux系统&#xff1f; 为什么Linux系统被嵌入式设备广泛应用&#xff1f; 系统调用 应用层是什么&#xff1f; 系统调用和库函数有什么区别&#xff1f; 为什么在应用层不能直接调用内核中的函数&#xff1f; 为什么有了系统调用就安全了…

Linux系统安装MySQL8.0

1.查看Linux发行版 2.安装前准备 2.1.检查是否安装 rpm -qa | grep mysql 2.2.如已安装mysql&#xff0c;则删除 rpm -e --nodeps 包名 2.3.再次检查安装包是否全部删除 rpm -qa | grep mysql 2.4.搜索mysql文件夹 find / -name mysql 2>/dev/null 2.5.若有mysql文件夹&a…