C++ 写个游戏引擎—(基础篇)thirteen

c++ 提供了变量 copy (复制)方式,当然是有一定的原因。 copy 在某些场景是很有好的解决方案,但相反一面,多数情况我们也应尽量避免 copy,因为 copy 会浪费时间,降低效率。毕竟我们写 c++的目的就是追求效率。 

现在我们看一下 c++ 是如何实现 copy 的,如果了解了 copy 的实现方式,我们就能更好地使用 copy 和合理地避免滥用 copy。

开始代码演示

8207483-9cb8050868de2d09

 对于基本数据类型:定义一个基本类型变量 a ,然后将变量 b 等于 a,这时变量 b 是 a 的 copy。但 a 和 b 指向不同的内存地址,所以当更改了变量 b 的值,不会影响到变量 a。

8207483-5f5b74a726fecf68

对于复合数据类型:class/struct 和基本类型是一样的,我们将 a 的 copy 一份复制给 b, a 和 b 还是指向不同内存的地址。

8207483-a96d28702a533381

我们可以在堆内存中创建一个 Vector2 实例,将创建好的 Vector2 对象用内存指针地址 a。  这里b copy 的 a 指向的内存的地址,也就是 a b 都是指向一个内存地址。所以当修改了 b->x 属性值,也就是等于修改了 a->x 的属性值。可以想象我们这里,是将以一个引用赋值给另一个引用,他们都引用相同的内存地址。

8207483-f0b17f2d2b7c1225

接下来,进一步讨论一下 copy,现在自己来实现一个 String 类。首先我们明确一下 String 应该是由一系列字母组成的,所以在 private 定义指针 m_Buffer 用于保存 char 类型数据,再定义 m_Size 为 String 包含字母的数量。

String 构造函数接受指针 string (为 chart 类型数组)构造函数中要做两件事,第一件就是计算字符串的长度,然后赋值给 m_Size ,然后就是将 string 指针指向内存地址中的数据赋值给 m_Buffer。我们可以for循环 string 然后将 string 中内容赋值给 m_Buffer。

这里 memcpy 接受三个参数,第一个参数为复制的目标,第二个参数复制的源,第三参数为复制的长度。

8207483-0cb58fcb726a04f2

创建好 String 的构造函数,我们还需让 String 可以输出 m_Buffer 中的内容。

8207483-dd5412b2ff21f8dd

这里使用 friend ,以便函数可以调用 string 类中的 private 属性 m_Buffer。

8207483-93785c84bb327d22

将 GetBuffer() 方法替换为 m_Buffer 以输出 m_Buffer 中的内容。

8207483-280bb152acc52754

由于没有标识字符串结束(也就是字母组成的数组)这里才会有除了 jangwoo 后面的其他符号。连续内存地址中存储字符组成的字符串,最后应该有用 0 占位的内存地址。表示字符串结束。

8207483-611259fe5f61ca5d

要处理掉这个问题很简单,只需要在为 m_Buffer 分配地址时加上一个字节,即可。表示字符串结束。

8207483-755297bf8c4739b4
8207483-00c024118e082921

由于 m_Buffer 是通过 new 关键字创建的,占用堆内存。我们需要在 String 的析构函数中将 m_Buffer 占用的内存释放掉。

8207483-31dc833d1a5384c6

创建String 类型的变量 string 赋值为 “jangwoo" ,然后 string 赋值给变量 second。试着在终端输出 string 和 second 。运行程序,发现报错了

8207483-d631e4f920280032

解释一下吧,同一个类型变量 second 和 string 经过复制后,这两个变量中保存的 m_buffer 变量指向同一个内存地址。

8207483-1f65b8e22d969dce
8207483-0824a30fa4f80da3
8207483-8d3ab52f2108b510

我们为 String 类型添加一个方法,这个方法用于根据 index 获取对应位置上字符。

8207483-7fce653454187d7a
8207483-509ef42045425f01

这里复制是浅复制,所以当执行到析构函数,就会重复释放 m_Buffer 两次,因此才报错。我们需要深复制来避免这个问题。要实现深度复制,我们需要创建一个构造函数 String 在这个构造函数我们新建 m_Buffer ,这样就不会指向一个同一个 m_Buffer 的内存地址。

8207483-f3d5a9483c99ea79
8207483-4336af4e8c85cb3d
8207483-86c22efb720f2eeb
8207483-e9372d0355461bee
8207483-ac479b5d077224f0

猜你喜欢

转载自blog.csdn.net/weixin_34008933/article/details/87340130