C++深浅拷贝和string类的两种写法详解

目录
  • 一、深浅拷贝
  • 二、string类的两种写法
    • 1.传统写法
    • 2.现代写法
  • 总结

一、深浅拷贝

拷贝这个词对于我们来说应该不陌生,比如我们平常的复制和粘贴就是拷贝;但是如果把拷贝这个词放到C++中来说就有一些复杂了,我们先来看一下什么是浅拷贝:

下面用字符串类来模拟实现。

class Astring
{
public:
	//构造函数
	Astring(const char* str = "")
	{
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	//采用浅拷贝写的构造函数
	Astring(const Astring& s)
	{
		_str = s._str;
	}
	//析构函数
	~Astring()
	{
		delete[] _str;
		_str = nullptr;
	}
private:
	char* _str;
};
int main()
{
	Astring aa("hello C++");
	Astring bb(aa); //这里调用拷贝构造
	return 0;
}

当我们执行以上程序的话就会失败,结果如下:

分析如下图所示:

所以我们采用浅拷贝使用同一块空间是不行了,那么怎么办呢?当然是重新开一块和别人同样大小的空间,然后再把别人空间里面的内容给拷贝过来,而这样就是所谓的深拷贝了;我们还是用字符串类来模拟实现深拷贝:

class Astring
{
public:
	//构造函数
	Astring(const char* str = "")
	{
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	//采用深拷贝写的构造函数
	Astring(const Astring& s)
	{
		_str = new char[strlen(s._str) + 1];
		strcpy(_str, s._str);
	}
	//析构函数
	~Astring()
	{
		delete[] _str;
		_str = nullptr;
	}
private:
	char* _str;
};

int main()
{
	Astring aa("hello C++");
	Astring bb(aa);
	return 0;
}

分析如下图所示:

二、string类的两种写法

有了上面我们知道的深浅拷贝,所以我们明白类中的拷贝构造函数和赋值重载一定要用深拷贝来实现,不过拷贝构造函数和赋值重载还是有两种写法的。

1. 传统写法

传统写法就是要自己开辟空间自己来拷贝别人的东西,什么事情都要自己干,代码如下:

//搞一个命名空间,里面实现自己写的string类
namespace cjy
{
	class string
	{
	public:
		//构造函数
		string(const char* str = "")
			:_str(new char[strlen(str) + 1])
		{
			strcpy(_str, str);
		}
		//拷贝构造函数
		string(string& s)
			:_str(new char[strlen(s._str) + 1])
		{
			strcpy(_str, s._str);
		}
		//赋值重载,s1=s3
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[strlen(s._str) + 1];
				delete[] _str;
				_str = tmp;
				strcpy(_str, s._str);
			}
			return *this;
		}
		//析构函数
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}
	private:
		char* _str;
	};
}

2. 现代写法

现代写法就是复用其它的函数,自己不用干活,交给其它函数来帮你实现,代码如下:

//现代写法:拷贝构造、赋值重载函数
namespace cjy
{
	class string
	{
	public:
		//构造函数
		string(const char* str = "")
		{
			_str = new char[strlen(str) + 1];
			strcpy(_str, str);
		}
		//拷贝构造函数
		string(const string& s)
			:_str(nullptr)
		{
			string tmp(s._str);
			std::swap(_str, tmp._str);
     	}
		//赋值重载
		string& operator=(string s)
		{
			std::swap(_str, s._str);
			return *this;
		}
	private:
		char* _str;
	};
}

分析如下图所示:

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++深浅拷贝和写时拷贝图文详解

    前言 之前我们在浅谈6个成员函数中有提到深浅拷贝的问题,现在再回首掏一把. 一.深浅拷贝哪家强? 先给出代码理一理 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<assert.h> using namespace std; class String { friend ostream& operator<<(ostream &out, const String &s);

  • c++中深浅拷贝以及写时拷贝的实现示例代码

    本文主要给大家介绍了关于c++中深浅拷贝及写时拷贝实现的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一:浅拷贝&深拷贝 浅拷贝:在拷贝构造的时候,直接将原内容的地址交给要拷贝的类,两个类共同指向一片空间.但是存在很大的缺陷:①一旦对s2进行操作,s1的内容也会改变:②析构时先析构s2,再析构s1,但是由于s1,s2指向同一片空间,会导致一片空间的二次析构导致出错. 深拷贝:通过开辟和源空间大小相同的空间并将内容拷贝下来再进行操作.不论是否对s2进行操作,都会拷贝一片相

  • c++编写String类代码实例

    本文实例为大家分享了c++编写String类的具体代码,供大家参考,具体内容如下 class String { public: String(const char* = nullptr); //普通构造函数 String(const String& other); //拷贝构造函数 ~String(void); //析构函数 String& operator = (const String& other); //赋值函数 private: char* m_data; }; //普通

  • C++ 系统String类详解

    目录 一.C++ 系统String类 1.定义及初始化 2.类型大小 3.常用运算 1.赋值 2.加法 3.关系 4.常见的成员函数 1.下标操作 2.求串大小 3.返回c串(c语言中的字符串也叫c串) 4.查找 5.删除 6.交换swap 5.string类型数组 总结 一.C++ 系统String类 除了使用字符数组来处理字符串以外,c++引入了字符串类型.可以定义字符串变量. 1.定义及初始化 #include <iostream> #include <string.h> u

  • 带你粗略了解C++中的深浅拷贝

    目录 一. 背景 二. 代码实现 三. 问题 四. 解决方法 总结 一. 背景 首先看这样一个问题,在Car类中聚合了Engine类 二. 代码实现 下面给出类Car与类Engine的定义 Car.h #ifndef COPY__CAR_H_ #define COPY__CAR_H_ #include "Engine.h" #include <string> using namespace std; class Car { public: // 构造函数 Car(); Ca

  • C++中的string类型

    目录 1.string 类 1.1 和char *的异同 1.2 C++11初始化 1.3 拼接 1.4 长度 1.5 IO 1.6 原始字符串 1.string 类 1.1 和char *的异同 在C++当中,除了char *类型,还有专门的字符串类型,就叫做string. 通过包含头文件string就可以使用: include<string> 在很多方面,string类型的使用方法和char *一样,例如: string str1; string str2 = "hello wo

  • C++深浅拷贝和string类的两种写法详解

    目录 一.深浅拷贝 二.string类的两种写法 1.传统写法 2.现代写法 总结 一.深浅拷贝 拷贝这个词对于我们来说应该不陌生,比如我们平常的复制和粘贴就是拷贝:但是如果把拷贝这个词放到C++中来说就有一些复杂了,我们先来看一下什么是浅拷贝: 下面用字符串类来模拟实现. class Astring { public: //构造函数 Astring(const char* str = "") { _str = new char[strlen(str) + 1]; strcpy(_st

  • RabbitMQ 实现延迟队列的两种方式详解

    目录 1. 用插件 1.1 安装插件 1.2 消息收发 2. DLX 实现延迟队列 2.1 延迟队列实现思路 2.2 案例 3. 小结 定时任务各种各样,常见的定时任务例如日志备份,我们可能在每天凌晨 3 点去备份,这种固定时间的定时任务我们一般采用 cron 表达式就能轻松的实现,还有一些比较特殊的定时任务,向大家看电影中的定时炸弹,3分钟后爆炸,这种定时任务就不太好用 cron 去描述,因为开始时间不确定,我们开发中有的时候也会遇到类似的需求,例如: 在电商项目中,当我们下单之后,一般需要

  • Java求最小生成树的两种算法详解

    目录 1 最小生成树的概述 2 普里姆算法(Prim) 2.1 原理 2.2 案例分析 3 克鲁斯卡尔算法(Kruskal) 3.1 原理 3.2 案例分析 4 邻接矩阵加权图实现 5 邻接表加权图实现 6 总结 介绍了图的最小生成树的概念,然后介绍了求最小生成树的两种算法:Prim算法和Kruskal算法的原理,最后提供了基于邻接矩阵和邻接链表的图对两种算法的Java实现. 阅读本文需要一定的图的基础,如果对于图不是太明白的可以看看这篇文章:Java数据结构之图的原理与实现. 1 最小生成树的

  • 基于ScheduledExecutorService的两种方法(详解)

    开发中,往往遇到另起线程执行其他代码的情况,用java定时任务接口ScheduledExecutorService来实现. ScheduledExecutorService是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响. 注意,只有当调度任务来的时候,ScheduledExecutorService才会真正启动一个线程,其余时间ScheduledExecutorService都是处于轮询任务的状态. 1.scheduleAtFix

  • 使用Java构造和解析Json数据的两种方法(详解二)

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式.同时,JSON是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON数据不须要任何特殊的 API 或工具包. 在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Json数据的方法

  • springboot 注册服务注册中心(zk)的两种方式详解

    在使用springboot进行开发的过程中,我们经常需要处理这样的场景:在服务启动的时候,需要向服务注册中心(例如zk)注册服务状态,以便当服务状态改变的时候,可以故障摘除和负载均衡. 我遇到过两种注册的途径: 1.在Spring的webapplication启动完成后,直接进行注册: 2.在servlet容器启动完成后,通过listener进行注册. 本文通过一个demo讲述一下这两种注册方式,使用的是传统的向zk注册的方案. 1.Spring webapplication启动完成后注册 先上

  • mapper接口注入两种方式详解

    这篇文章主要介绍了mapper接口注入两种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.使用模板方式: <!--使用模板类实现mybatis --> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFacto

  • Spring Bean属性注入的两种方式详解

    目录 属性注入概念 一.构造器注入 示例1 注意点 二.setter注入 示例2 三.如何选择注入方式 属性注入概念 Spring 属性注入(DI依赖注入)有两种方式:setter注入,构造器注入. 这个注入的属性可以是普通属性(基本数据类型与String等),也可以是一个引用数据类型(主要是对象),或者是一个集合(list.map.set等) 下表是属性注入bean标签中常用的元素 元素名称 描述 constructor-arg 构造器注入.该元素的 index 属性指定构造参数的索引(从 0

  • SpringBoot处理接口幂等性的两种方法详解

    目录 1. 接口幂等性实现方案梳理 1.1 基于 Token 1.2 基于请求参数校验 2. 基于请求参数的校验 在上周发布的 TienChin 项目视频中,我和大家一共梳理了六种幂等性解决方案,接口幂等性处理算是一个非常常见的需求了,我们在很多项目中其实都会遇到.今天我们来看看两种比较简单的实现思路. 1. 接口幂等性实现方案梳理 其实接口幂等性的实现方案还是蛮多的,我这里和小伙伴们分享两种比较常见的方案. 1.1 基于 Token 基于 Token 这种方案的实现思路很简单,整个流程分两步:

  • Spring框架实现AOP的两种方式详解

    目录 第一种AOP实现方式 AfterLog Log 配置文件 实例调用 定义接口 第二种AOP实现方式 第一种AOP实现方式 AfterLog package com.xxx.demo.service1; import org.junit.After; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements Aft

随机推荐