0
点赞
收藏
分享

微信扫一扫

Cherno C++ P44 C++的复制与拷贝构造函数

YouTube视频链接

C++的复制与拷贝构造函数

本文是ChernoP44视频的学习笔记。
  看如下代码,a和b是两个独立的变量,它们有不同的内存地址,若将b=3则a仍然是2。在Vector2类中是同样的原理,c.x仍然会是2。若要在堆中使用new关键字来进行分配则复制了指针,e和f两个指针本质上有相同的值(内存地址),但是如果访问这个内存地址并设为某个值,则会同时影响e和f。

#include<iostream>
#include<string>
#include<memory>

struct Vector2
{
	float x, y;
};

int main()
{
	int a = 5;
	int b = a;

	Vector2 c = { 2,3 };
	Vector2 d = c;
	d.x = 5;

	Vector2* e = new Vector2();
	Vector2* f = e;
	f->x = 2;

	std::cin.get();
}

  若使用C++原始特性写一个字符串类,使用标准的std::cout来打印字符串,所以重载左移字符串。将运算符的重载函数作为这个类的友元,就可以从函数中访问m_Buffer。

#include<iostream>

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];
	    memcpy(m_Buffer, string, m_Size);
	}

	~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 string = "Cherno";
	std::cout << string << std::endl;

	std::cin.get();
}

  按下F5运行代码,打印了Cherno但是伴随着很多随机字符,这是因为没有空终止字符。
在这里插入图片描述  所以要把空终止字符添加上,在分配缓冲区的时候将m_Size+1(也可以使用strcpy函数)。
在这里插入图片描述  也可以写m_Buffer[m_Size]=0,手动在最后添加自己的空终止。
在这里插入图片描述

浅拷贝

  试着复制这个字符串叫它second,然后把它们打印出来。按F5可以看到打印了两次Cherno。
在这里插入图片描述  但如果按回车键,代码执行完cin.get()之后,代码就会崩溃。
在这里插入图片描述  当我们复制这个String时,C++自动为我们做的是将所有类成员变量复制到一个新的内存地址里面,这个新的内存地址包含了second字符串。现在内存中有两个String,因为它们直接进行复制,这种复制被称为浅拷贝,它所做的是复制这个指针内存中的两个String对象,它们有相同的char*的值,也就是相同的地址。这个m_Buffer的内存地址,对于这两个String对象来说是相同的,程序会崩溃。当我们到达作用域的尽头时,两个String都被销毁了,析构函数会被调用,执行两次delete[] m_Buffer,程序试图两次释放同一个内存块所以会崩溃。
  在34行设置断点,发现string和second的m_Buffer地址一样。
在这里插入图片描述在这里插入图片描述
  若想要修改second字符串,访问第二个索引并把它赋值a,为了让[]操作符起作用,需要操作符重载。按下F5出现两个Charno,为什么会有两个同样的Charno?而且程序还是崩溃了。看起来我们复制了但没有完全复制。
在这里插入图片描述

深拷贝

  我们需要做的是分配一个新的char数组来存储复制的字符串,而现在做的只是复制指针,两个字符串对象指向完全相同的内存缓冲区。若希望第二个字符串拥有自己的指针以拥有唯一的内存块,当修改或删除第二个字符串时不会触及第一个字符串。这里需要执行一种叫做深度复制(深拷贝)的东西,使用拷贝构造函数,拷贝构造函数是一个构造函数,当复制第二个字符串时它会被调用。当把一个字符串赋值给一个对象时,这个对象也是一个字符串。当试图创建一个新的变量并给它分配另一个变量时,它和正在创建的变量有相同的类型。复制这个变量也就是所谓的拷贝构造函数。
  c++默认提供一个拷贝构造函数,拷贝构造函数的函数签名对同样的类对象的常引用const &。它的作用是内存复制,将other对象的内存浅层拷贝进这些成员变量。

String(const String& other)//拷贝构造函数
		:m_Buffer(other.m_Buffer), m_Size(other.m_Size) {}

  这样不行,因为不仅仅想复制指针还想复制指针所指向的内存。我们要做的是找到我们自己的拷贝构造函数进行深拷贝。

	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);
	}

  按F5运行代码发现有Cherno和Charno两个字。当我们改变第二个字符串时没有改变第一个字符串,按下回车键也不会崩溃。
在这里插入图片描述

举报

相关推荐

0 条评论