c++ 提供了变量 copy (复制)方式, 当然是有一定的原因. copy 在某些场景是很有好的解决方案, 但相反一面, 多数情况我们也应尽量避免 copy, 因为 copy 会浪费时间, 降低效率. 毕竟我们写 c++ 的目的就是追求效率.
现在我们看一下 c++ 是如何实现 copy 的, 如果了解了 copy 的实现方式, 我们就能更好地使用 copy 和合理地避免滥用 copy.
开始代码演示
对于基本数据类型: 定义一个基本类型变量 a , 然后将变量 b 等于 a, 这时变量 b 是 a 的 copy. 但 a 和 b 指向不同的内存地址, 所以当更改了变量 b 的值, 不会影响到变量 a.
对于复合数据类型: class/struct 和基本类型是一样的, 我们将 a 的 copy 一份复制给 b, a 和 b 还是指向不同内存的地址.
我们可以在堆内存中创建一个 Vector2 实例, 将创建好的 Vector2 对象用内存指针地址 a. 这里 b copy 的 a 指向的内存的地址, 也就是 a b 都是指向一个内存地址. 所以当修改了 b->x 属性值, 也就是等于修改了 a->x 的属性值. 可以想象我们这里, 是将以一个引用赋值给另一个引用, 他们都引用相同的内存地址.
接下来, 进一步讨论一下 copy, 现在自己来实现一个 String 类. 首先我们明确一下 String 应该是由一系列字母组成的, 所以在 private 定义指针 m_Buffer 用于保存 char 类型数据, 再定义 m_Size 为 String 包含字母的数量.
String 构造函数接受指针 string (为 chart 类型数组)构造函数中要做两件事, 第一件就是计算字符串的长度, 然后赋值给 m_Size , 然后就是将 string 指针指向内存地址中的数据赋值给 m_Buffer. 我们可以 for 循环 string 然后将 string 中内容赋值给 m_Buffer.
这里 memcpy 接受三个参数, 第一个参数为复制的目标, 第二个参数复制的源, 第三参数为复制的长度.
创建好 String 的构造函数, 我们还需让 String 可以输出 m_Buffer 中的内容.
这里使用 friend , 以便函数可以调用 string 类中的 private 属性 m_Buffer.
将 GetBuffer() 方法替换为 m_Buffer 以输出 m_Buffer 中的内容.
由于没有标识字符串结束 (也就是字母组成的数组) 这里才会有除了 jangwoo 后面的其他符号. 连续内存地址中存储字符组成的字符串, 最后应该有用 0 占位的内存地址. 表示字符串结束.
要处理掉这个问题很简单, 只需要在为 m_Buffer 分配地址时加上一个字节, 即可. 表示字符串结束.
由于 m_Buffer 是通过 new 关键字创建的, 占用堆内存. 我们需要在 String 的析构函数中将 m_Buffer 占用的内存释放掉.
创建 String 类型的变量 string 赋值为 "jangwoo" , 然后 string 赋值给变量 second. 试着在终端输出 string 和 second . 运行程序, 发现报错了
解释一下吧, 同一个类型变量 second 和 string 经过复制后, 这两个变量中保存的 m_buffer 变量指向同一个内存地址.
我们为 String 类型添加一个方法, 这个方法用于根据 index 获取对应位置上字符.
这里复制是浅复制, 所以当执行到析构函数, 就会重复释放 m_Buffer 两次, 因此才报错. 我们需要深复制来避免这个问题. 要实现深度复制, 我们需要创建一个构造函数 String 在这个构造函数我们新建 m_Buffer , 这样就不会指向一个同一个 m_Buffer 的内存地址.
来源: http://www.jianshu.com/p/16c2743ccf4a