对象应用:C++字符串和vector,对象的new与delete重构

对象应用

  • C++字符串和vector
    • 字符串创建方式
    • 字符串拼接
      • 字符串追加
    • 字符串截断
    • auto
    • vector创建方式
    • vector操作
  • new与delete重构
    • new与delete的工作步骤
    • new与delete重构应用
      • 只能生成栈对象
      • 只能生成堆对象

C++字符串和vector

C++的字符串是一个对象,存在于std标准库中,是std标准库提供的自定义类类型
所占存储空间较大,40字节,数据成员一般都包含
在这里插入图片描述
vector是一种动态数组,也存在与std标准库中,一般都有size和capacity两个数据成员

字符串创建方式

默认创建

string s1;

C语言字符串创建

string s2("Hello");

指定长度的单个字符创建

string s3(10,'a');

字符串拼接

只能用+拼接,+两边必须有一个是string类对象

	string s4 = s3 + s2;
	s4 = s3 + "Hello";
	s4 = "Hello" + s3;

字符串追加

追加特定长度字符

s3.append(3,'a');

追加字符串

s3.append("Hello");

追加string类对象

s3.append(s2);

追加string类对象指定起始位置指定长度

s3.apend(s2,0,5);

字符串截断

//参数1,pos,指定起始位置,参数2,len,指定长度

cout<<s3.substr(0,3)<<endl;

auto

C++的一种自动遍历模式,auto是自动推导,如果不带引用可能会浪费空间

for(auto& t: s3)
{
	cout<<t<<' ';
}

完整代码

#include <iostream>

using std::cout;
using std::endl;
using std::string;
//std::string 标准库提供的自定义类类型

void sp(string& s)
{
	cout << "s:" << s << endl;
	cout << "s:sizeof:" << sizeof(s) << endl;
	cout << "s.size:" << s.size() << endl;
	cout << "s.length:" << s.length() << endl;

	cout << endl;
}
int main()
{
	//三种构造函数
	string s1;
	string s2("Hello");//c -to c++
	string s3(10, 'a');

	sp(s1);
	sp(s2);
	sp(s3);

	//字符串拼接
	string s4 = s3 + s2;
	s4 = s3 + "Hello";
	s4 = "Hello" + s3;
	sp(s4);
	//操作运算符两边必须有一个是string对象

	//追加	
	s3.append(3, 'a');//追加字符
	sp(s3);
	s3.append("Hello");//追加字符串
	s3.append(s2);//追加string对象
	s3.append(s2,0,5);//追加特定起始位置特定长度的string对象
	sp(s3);

	//截断
	cout << s3.substr(0, 3) << endl;//参数一pos,参数2len

	cout << &s1 << endl;//对对象取地址,得到是对象首地址,而不是字符串内容首地址

	cout << endl;

	//auto是自动推导,&是引用,没有引用会浪费内存
	for (auto& t : s3)
	{
		cout << t << ' ';
	}
	return 0;
}

vector创建方式

默认创建

vector<int> numbers;

初始化创建

vector<int> numbers(10,0);//创建大小为10的数组,数组元素皆为0,vector容量为10

vector操作

添加元素

numbers.push_back(1);

删除末尾元素

numbers.pop_back();

代码实现

#include <iostream>
#include <vector>

using std::cout;
using std::endl;
using std::vector;

void vp(vector<int>& numbers)
{
	cout << "numbers:size:" << numbers.size() << endl;
	cout << "numbers.capacity:" << numbers.capacity() << endl;

}
int main()
{
	vector<int> numbers;
	vp(numbers);

	for (int i = 0; i < 10; ++i)
	{
		numbers.push_back(i);
		vp(numbers);
	}

	//初始化操作
	vector<int> a(11, 0);
	for (auto& t : a) cout << t << ' ';

	vp(a);

	return 0;
}

有一个需要我们值得注意的地方
vector对象在size为capacity时且还需要再添加新的元素时,会进行扩容

扩容步骤
申请一个原先x倍的空间
将旧空间的元素拷贝到新空间中
销毁旧空间,vector数组指向新空间

不同编译器在扩容时的倍率不同
在这里插入图片描述
在这里插入图片描述
可以看到,一般的编译器扩容一般都是2倍扩容,而vs会以原来的1.5倍扩容

new与delete重构

new与delete的工作步骤

new:

1.调用operator new标准库函数申请未定义的空间
2.在该空间调用构造函数初始化对象
3.返回一个相应类型的指针
形式 void* operator new(size_t)

delete

调用析构函数
调用operator delete标准库函数回收对象空间

代码实现

#include <iostream>
#include <cstdlib>
#include <cstring>

using std::cout;
using std::endl;

class Student
{
public:
	Student(const char* name,const int& id)
	:_name(new char[strlen(name) + 1]())
	,_id(id)
	{
		strcpy(_name,name);
		cout<<"Have done create"<<endl;
	}

	void release()
	{
		delete[] _name;
		_name = nullptr;
	}
	~Student()
	{
		if(_name) release();
		cout<<"~Student"<<endl;
	}
	
	void print() const
	{
		cout << "name:" << _name << endl;
		cout << "id:" << _id << endl;
	}
	
	void* operator new(size_t sz)
	{
		cout<<"Operator new"<<endl;
		return malloc(sz);
	}
	void operator delete(void* p)
	{
		cout<<"Operator delete"<<endl;
		free(p);
	}
private:
	char* _name;
	int _id;
}
int main()
{
	return 0;
}

size_t 类型无需担心会不会申请出错

new与delete重构应用

生成栈对象的条件

1.需要合法的构造函数
2.需要合法的析构函数

生成堆对象的条件

1.需要合法的operator new库函数
2.需要合法的构造函数

只能生成栈对象

方法:将 operator new库函数私有化

#include <iostream>
#include <cstdlib>
#include <cstring>

using std::cout;
using std::endl;

class Student
{
public:
	Student(const char* name,const int& id)
	:_name(new char[strlen(name) + 1]())
	,_id(id)
	{
		strcpy(_name,name);
		cout<<"Have done create"<<endl;
	}

	void release()
	{
		delete[] _name;
		_name = nullptr;
	}
	~Student()
	{
		if(_name) release();
		cout<<"~Student"<<endl;
	}
	
	void print() const
	{
		cout << "name:" << _name << endl;
		cout << "id:" << _id << endl;
	}
private:
	char* _name;
	int _id;
	void* operator new(size_t sz){}//因为不需要创建堆对象,所以去重构的过程没有意义,只需要在private内声明即可
	void operator delete(void* p){}
};

void test1()
{
	Student s1("Rose",100);
	s1.print();
}
int main()
{
	test1();
	return 0;
}

打印结果

Have done create
name:Rose
id:100
~Student

只能生成堆对象

方法:将析构函数私有化

#include <iostream>
#include <cstdlib>
#include <cstring>

using std::cout;
using std::endl;

class Student
{
public:
	Student(const char* name,const int& id)
	:_name(new char[strlen(name) + 1]())
	,_id(id)
	{
		strcpy(_name,name);
		cout<<"Have done create"<<endl;
	}

	void release()
	{
		delete[] _name;
		_name = nullptr;
	}

	
	void print() const
	{
		cout << "name:" << _name << endl;
		cout << "id:" << _id << endl;
	}
	void* operator new(size_t sz)
	{
		malloc(sz);
		cout<<"Operator new"<<endl;
	}
	void operator delete(void *p)
	{
		delete p;
		cout<<"Operator delete"<<endl;
	}
private:
	char* _name;
	int _id;
		~Student()
	{
		if(_name) release();
		cout<<"~Student"<<endl;
	}
};

void test2()
{
	Student* sp1 = new Student("Jackie",101);
	sp1->print();
	sp1->delete;
}
int main()
{
	test2();
	return 0;
}

此时我们运行发现,在sp1->delete行出错,由此我们知道delete在销毁对象时调用了析构函数,而析构函数因为他的私有化而不可用,因此需要在public里新建一个函数用来替换delete操作

void destroy()
{
	this->~Student();
}

此时我们在内存检测时发现,对象本身没有被真正销毁,因此在destroy内部调用析构函数是错误的,应该直接进行delete操作,由于是在类的内部进行delete,可以访问析构函数,所以其操作是完全可行的

void destroy()
{
	delete this;
}

代码实现

#include <iostream>
#include <cstring>

using std::cout;
using std::endl;

//new 和 delete 都是用operator的标准库函数

class Student {
public:

	Student(const char* name, const int& id)
		:_name(new char[strlen(name) + 1]())
		, _id(id)
	{
		strcpy(_name, name);
		cout << "Have done create!" << endl;
	}
	void release()
	{
		delete[] _name;
		_name = nullptr;
	}

	void destroy()
	{
		//直接调用析构函数不能销毁对象
		//this->~Student();
		delete this;
	}

	void print() const
	{
		cout << "name:" << _name << endl;
		cout << "id:" << _id << endl;
	}
	//这里的new和delete只针对该类的创建销毁,放在全局定义时则会变成对全部的new和delete重构
	void* operator new(size_t sz)//不创建就会系统默认提供
	{
		cout << "Operator new" << endl;
		return malloc(sz);
	}
	void operator delete(void* p)
	{
		cout << "Operator delete" << endl;
		free(p);
	}
private:
	char* _name;
	int _id;

	~Student()
	{
		if (_name) release();

		cout << "Have done delete" << endl;
	}
};
void test2()
{
	//创建堆对象的条件
	//需要合法的operator new库函数
	//需要合法的构造函数
	Student* sp1 = new Student("Jackie", 100);
	sp1->print();
	sp1->destroy();	
	//delete sp1; 因为私有化,delete不可用,需要优化

	//如何让一个类只能生成栈对象,不能生成堆对象
	//解决方案
	//将operator new库函数私有化
}
int main()
{
	//new的工作步骤
	//调用operator new标准库函数申请未定义类型的空间
	//在该空间调用构造函数初始化对象
	//返回一个相应类型的指针
	//形式:void* operator new(size_t)


	//delete工作步骤
	//调用析构函数
	//调用operator delete标准库函数回收对象空间


	test2();

	return 0;
}

打印结果

Operator new
Have done create!
name:Jackie
id:100
Have done delete
Operator delete

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

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

相关文章

[echarts] legend icon 自定义的几种方式

echarts 官方配置项 地址 一、默认 图例项的 icon circle, rect, roundRect, triangle, diamond, pin, arrow, none legend: {top: 5%,left: center,itemWidth: 20,itemHeight: 20,data: [{icon: circle, name: 搜索引擎},{icon: rect, name: 直接访问},{icon: roundRect, n…

什么是FPGA?关于FPGA基础知识 一起来了解FPGA lattice 深力科 MachXO3系列 LCMXO3LF-9400C-5BG256C

什么是FPGA&#xff1f;关于FPGA基础知识 一起来了解FPGA lattice 深力科 MachXO3系列 LCMXO3LF-9400C-5BG256C FPGA基础知识&#xff1a;FPGA是英文Field&#xff0d;Programmable Gate Array的缩写&#xff0c;即现场可编程门阵列&#xff0c;它是在PAL、GAL、CPLD等可编程器…

二叉排序树查找成功和不成功的平均查找长度

理解二叉树的特性: 1)结点:包含一个数据元素及若干指向子树分支的信息。 2)结点的度:一个结点拥有子树的数据成为结点的度。 3)叶子结点:也称为终端结点,没有子树的结点或者度为零的结点。 4)分支结点:也称为非终端结点,度不为零的结点成为非终端结点。 5)结点…

【一起撸个DL框架】5 实现:自适应线性单元

CSDN个人主页&#xff1a;清风莫追欢迎关注本专栏&#xff1a;《一起撸个DL框架》GitHub获取源码&#xff1a;https://github.com/flying-forever/OurDL 文章目录 5 实现&#xff1a;自适应线性单元&#x1f347;1 简介2 损失函数2.1 梯度下降法2.2 补充 3 整理项目结构4 损失函…

DAD-DAS模型

DAD-DAS模型 文章目录 DAD-DAS模型[toc]1 产品服务:需求方程2 实际利率:费雪方程3 通货膨胀:菲利普斯方程4 预期通货膨胀&#xff1a;适应性预期5 货币政策规则&#xff1a;泰勒方程6 动态总供给-总需求方程&#xff08;DAS-DAD&#xff09;7 总供给冲击模拟 1 产品服务:需求方…

Elasticsearch:NLP 和 Elastic:入门

自然语言处理 (Natural Language Processing - NLP) 是人工智能 (AI) 的一个分支&#xff0c;专注于尽可能接近人类解释的理解人类语言&#xff0c;将计算语言学与统计、机器学习和深度学习模型相结合。 AI - Artificial Inteligence 人工智能ML - Machine Learning 机器学习DL…

永远不该忘记!科技才是硬道理,手中没有剑,跟有剑不用,是两回事

今天是全国防灾减灾日&#xff0c;距离2008年汶川大地震也已经过去15年了。但时至今日&#xff0c;看到那些图像视频资料&#xff0c;那种触及灵魂的疼痛仍是存在的&#xff0c;2008年的大地震在每个中国人身上都留下了无法抚平的伤疤。 2008年是所有中国人都无法忘记的一年&am…

Ims跟2/3G会议电话(Conference call)流程差异介绍

2/3G Conference call 合并(Merged)通话前,两路电话只能一路保持(Hold),一路通话(Active)。 主叫Merged操作,Hold的一路会变成Active,进入会议通话。 例如终端A跟C通话,再跟B通话,此时B就是Active状态,C从Active变成Hold状态。Merged进入会议通话后,C又从Hold变…

docker安装elasticsearch

前言 安装es么&#xff0c;也没什么难的&#xff0c;主要网上搜一搜&#xff0c;看看文档&#xff0c;但是走过的坑还是需要记录一下的 主要参考这三份文档&#xff1a; Running the Elastic Stack on Docker docker简易搭建ElasticSearch集群 Running Kibana on Docker …

Python-exe调用-控制台命令行执行-PyCharm刷新文件夹

文章目录 1.控制台命令行执行1.1.subprocess.Popen1.2.os.system()1.3.subprocess.getstatusoutput()1.4.os.popen() 2.PyCharm刷新文件夹3.作者答疑 1.控制台命令行执行 主要四种方式实现。 1.1.subprocess.Popen import os import subprocess cmd "project1.exe&qu…

只下载rpm包而不安装(用于内网虚拟机使用)

这里写目录标题 问题&#xff1a;解决&#xff1a;1. 安装yum-utils2. 下载rpm包3. 将rpm包拷贝到离线的虚拟机并安装 遇到的问题&#xff1a;1. error while loading shared libraries: libXXX.so.X: cannot open shared object file: No such file2. wrong ELF class: ELFCLA…

C++学习day--10 条件判断、分支

1、if语句 if 语句的三种形态 形态1&#xff1a;如果。。。那么。。。 #include <iostream> using namespace std; int main( void ) { int salary; cout << " 你月薪多少 ?" ; cin >> salary; if (salary < 20000) { cout <&…

【博客系统】页面设计(附完整源码)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、页面介绍 二、预期效果 1、博客列表页效…

大项目准备(2)

目录 中国十大最具发展潜力城市 docker是什么&#xff1f;能介绍一下吗&#xff1f; 中国十大最具发展潜力城市 按照人随产业走、产业决定城市兴衰、规模经济和交通成本等区位因素决定产业布局的基本逻辑&#xff0c;我们在《中国城市发展潜力排名&#xff1a;2022》研究报告…

websocket

&#x1f449;websocket_菜鸟教程*…*的博客-CSDN博客 目录 1、什么是Socket&#xff1f;什么是WebSocket&#xff1f; 2、WebSocket的通信原理和机制 3、WebSocket技术出现之前&#xff0c;Web端实现即时通讯的方法有哪些&#xff1f; 4、一个简单的WebSocket聊天小例子 …

prometheus监控数据持久化

前置条件 1.规划两台主机安装prometheus # kubectl get nodes --show-labels | grep prometheus nm-foot-gxc-proms01 Ready worker 62d v1.23.6 beta.kubernetes.io/archamd64,beta.kubernetes.io/oslinux,kubernetes.io/archamd64,kubernetes.io…

5款办公必备的好软件,你值得拥有

随着网络信息技术的发展&#xff0c;越来越多的人在办公时需要用到电脑了。如果你想提高办公效率&#xff0c;那么就少不了工具的帮忙&#xff0c;今天给大家分享5款办公必备的好软件。 1.文件管理工具——TagSpaces TagSpaces 是一款开源的文件管理工具,它可以通过标签来组织…

Linux一学就会——系统文件I/O

Linux一学就会——系统文件I/O 有几种输出信息到显示器的方式 #include <stdio.h> #include <string.h> int main() {const char *msg "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout);printf("hello printf\n");fprintf(stdout, &q…

体验洞察 | 原来它才是最受欢迎的CX指标?

一直以来&#xff0c;企业都在试图追踪他们能否在整个客户旅程中始终如一地提供卓越的客户体验&#xff08;Customer Experience&#xff0c;简称“CX”&#xff09;&#xff0c;并通过多个CX指标&#xff0c;如NPS&#xff08;净推荐值&#xff09;、CSAT&#xff08;客户满意…

openGL 环境搭建

刚入坑&#xff0c;每个包、每个项目都得重新配一遍&#xff0c;实在烦人&#xff0c;由于网上已有很多教程&#xff0c;故在此只简要介绍。 比较通用的安装方法如下&#xff1a; 优先下载&#xff0c;对应vs版本&#xff0c;32位&#xff0c;已经编译好的库。如果下载的是源代…