[STL]vector底层模拟实现的双层深拷贝细节剖析

4 篇文章 0 订阅
4 篇文章 0 订阅

memcpy实际上是一种值拷贝:在模拟实现的时候,拷贝构造和扩容如果都使用了mempy
所以在vector<T>模板T为内置类型的时候,不会出现问题
但如果是自定义类型的,特别是自定义类型中出现指针等,容易造成浅拷贝的问题

下面我们来分析:  

   这是一种原始形式的拷贝函数的写法:当遇到内置类型的函数时候是一点毛病没有,但是如果遇到自定类型,就会出现下面的情况

加入我们将类型改成string,去拷贝构造

 我们把v3拷贝给v4,如果用memcpy就会用第一层深拷贝实现了,但是第二层失败的情况:

重点分析: 

         v3和v4都有了自己独立的空间,此时第一层深拷贝完成;但是此时vector的元素类型是自定义类型string,string自己的_str还指向一篇动态开辟的空间,所以如果只是使用memcpy的话,就只能拷贝_str的值过去,但是新旧的_str指向的地址依旧是同一个,造成浅拷贝。

        所以我们为了处理这种情况,选择使用赋值操作去完成自定义类型数据的拷贝(注意:使用赋值去完成拷贝,应该先保证此种自定义类型自身已经重载了赋值操作,如果仅仅依靠编译器默认生成的赋值函数,不足以完成深拷贝的目的)

代码展示:

vector(const vector<T>& v)
		{
			_start = new T[v.capacity()];
			for (size_t i = 0; i < v.size(); i++)
			{
				_start[i] = v._start[i];
			}
			_finsh = _start + v.size();
			_end_of_storage = _start + v.capacity();
		}

         运用赋值的时候,会自动调用自定义类型的赋值成员函数,即对成员完成深拷贝操作。

        上面提到了,扩容操作(reserve)也是会导致出现第二层深拷贝失效,和上述是同样的道理,我们只要将memcpy改成赋值操作就可以了:

	void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();//提前把size记录下来
								//不然后面开新空间后的_start就不是原来的_start了,会找不到原来的size()
				T* tmp = new T[n];
				//如果原本空间里值不为空,那么用memcpy拷贝过去
				//memcpy(tmp, _start, sizeof(T) * size());
				if (_start)
				{
					for (size_t i = 0; i < sz; ++i)
					{
						tmp[i] = _start[i];
					}
				}

				delete[] _start;  

				_start = tmp;
				_finsh= _start + sz;
				_end_of_storage = _start + n;
			}
			
		}

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值