C++学习笔记(二十六):c++ 复制与拷贝构造函数

  • 本节介绍拷贝构造函数。
  • 当我们复制数据或对象是一般情况下我们会有两个副本。但当我们仅需要读取数据或者修改一个已经存在的对象时,我们不想去复制一份副本,这样会造成性能的损耗。理解什么时候复制,什么时候不需要复制对提升程序的性能有较大的帮助。
  • 接下来的示例展示复制操作以及不想复制的时候需要怎样去操作。
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

class Entity
{
public:
	int x, y;
	Entity(int x, int y)
	{
		this->x = x;
		this->y = y;
		std::cout << "这是构造函数!!!" << std::endl;
	}
	~Entity()
	{
		std::cout << "这是析构函数!!!" << std::endl;
	}
}; 


int main()
{
	//Entity e1(2,5);
	//Entity e2 = e1;
	//e2.x = 9;   //此时修改e2中属性变量的值不会影响e1,因为我们复制了一根Entity
	Entity *e1 = new Entity(2, 5);
	Entity* e2 = e1;
	e2->x = 4;  //此时修改e2中属性变量的值会影响e1,因为我们复制了e1的地址到e2,它两指向同样的地址

	std::cin.get();
	return 0;
}
  • 手动实现String类来展示copy操作

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

//自己实现string来更好的展示拷贝复制构造函数
class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1]; //+1是因为要添加一个空终止符
		memcpy(m_Buffer, string, m_Size); 
		m_Buffer[m_Size] = 0;
	}
	~String()
	{
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string) 
{
	stream << string.m_Buffer;
	return stream;
}

int main()
{
	String s1 = "pcop";
	/*
	下面这种方式进行copy操作会导致程序崩溃,因为在此处=操作进行的是浅拷贝,
	会导致两个String对象中的m_Buffer指向同一块内存地址,这样就会导致析构函数
	会对同一块内存地址释放两次
	*/
	String s2 = s1;  

	std::cin.get();
	return 0;
}
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

//自己实现string来更好的展示拷贝复制构造函数
class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1]; //+1是因为要添加一个空终止符
		memcpy(m_Buffer, string, m_Size); 
		m_Buffer[m_Size] = 0;
	}

	//拷贝构造函数
	String(const String& other)
		:m_Size(other.m_Size)
	{
		m_Buffer = new char[m_Size+1];
		memcpy(m_Buffer, other.m_Buffer, m_Size+1);
	}

	char& operator[] (int index)
	{
		return m_Buffer[index];
	}

	~String()
	{
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string) 
{
	stream << string.m_Buffer;
	return stream;
}

int main()
{
	String s1 = "pcop";
	/*
	* 如果不是先上诉的拷贝构造函数
	下面这种方式进行copy操作会导致程序崩溃,因为在此处=操作进行的是浅拷贝,
	会导致两个String对象中的m_Buffer指向同一块内存地址,这样就会导致析构函数
	会对同一块内存地址释放两次
	*/
	String s2 = s1;  
	/*
	* 下面操作修改s2的时候s1的值也会修改,因为两个String对象的m_Buffer指向同一块内存
	* 我们在复制中应该的操作是分配一块新的内存用来复制m_Buffer
	*/
	s2[2] = 'z';
	//解决上诉方法可以通过深拷贝来完成,本示例中通过拷贝构造函数来实现
	std::cout << s1 << std::endl;
	std::cout << s2 << std::endl;
	std::cin.get();
	return 0;
}
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

//自己实现string来更好的展示拷贝复制构造函数
class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1]; //+1是因为要添加一个空终止符
		memcpy(m_Buffer, string, m_Size); 
		m_Buffer[m_Size] = 0;
	}

	//拷贝构造函数
	String(const String& other)
		:m_Size(other.m_Size)
	{
		std::cout << "Copy String!!!" << std::endl;
		m_Buffer = new char[m_Size+1];
		memcpy(m_Buffer, other.m_Buffer, m_Size+1);
	}

	char& operator[] (int index)
	{
		return m_Buffer[index];
	}

	~String()
	{
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string) 
{
	stream << string.m_Buffer;
	return stream;
}

void PringString(const String& s)
{
	std::cout << s << std::endl;
}

int main()
{
	String s1 = "pcop";
	/*
	* 如果不是先上诉的拷贝构造函数
	下面这种方式进行copy操作会导致程序崩溃,因为在此处=操作进行的是浅拷贝,
	会导致两个String对象中的m_Buffer指向同一块内存地址,这样就会导致析构函数
	会对同一块内存地址释放两次
	*/
	String s2 = s1;  
	/*
	* 下面操作修改s2的时候s1的值也会修改,因为两个String对象的m_Buffer指向同一块内存
	* 我们在复制中应该的操作是分配一块新的内存用来复制m_Buffer
	*/
	s2[2] = 'z';
	//解决上诉方法可以通过深拷贝来完成,本示例中通过拷贝构造函数来实现

	/*
	* 如果 PringString(String& s)
	以下PringString方法调用的时候都会调用String的拷贝构造函数,每次需要分配新的内存
	会造成很大的性能浪费,我们只是想直接打印PringString方法的参数,不想通过复制。
	所以在PringString参数传递是直接传递引用  PringString(const String& s)
	*/
	PringString(s1);
	PringString(s2);
	std::cin.get();
	return 0;
}
相关推荐
StickToForever3 小时前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
黑不溜秋的5 小时前
C++ 设计模式 - 策略模式
c++·设计模式·策略模式
leegong231116 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
敲敲敲-敲代码6 小时前
【SQL实验】触发器
数据库·笔记·sql
Moonnnn.7 小时前
51单片机学习——动态数码管显示
笔记·嵌入式硬件·学习·51单片机
Dream it possible!8 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
南宫生8 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴8 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
王老师青少年编程8 小时前
【GESP C++八级考试考点详细解读】
数据结构·c++·算法·gesp·csp·信奥赛
技术小齐8 小时前
网络运维学习笔记 016网工初级(HCIA-Datacom与CCNA-EI)PPP点对点协议和PPPoE以太网上的点对点协议(此处只讲华为)
运维·网络·学习