vector实现——memcpy拷贝问题

vector实现完了函数,但是在进行测试时发现,如果使用自己的vector来完成一个杨辉三角的题目出现了问题:

myvector::vector<vector<int>> generate(int numRows) {
	myvector::vector<vector<int>> vv;
	//初始化vv前numRows
	vv.resize(numRows);
	//
	for (int i = 0; i < numRows; ++i)
	{
		vv[i].resize(i + 1, 0);
		vv[i][0] = vv[i][vv[i].size() - 1] = 1;
	}
	for (int i = 0; i < vv.size(); ++i)
	{
		for (int j = 0; j < vv[i].size(); ++j)
		{
			if (vv[i][j] == 0)
			{
				vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
			}
		}
	}

	return vv;
}

void test5()
{
	myvector::vector<vector<int>> vv = generate(5);
	for (int i = 0; i < vv.size(); ++i)
	{
		for (int j = 0; j < vv[i].size(); ++j)
		{
			cout << vv[i][j];
		}
		cout << endl;
	}
}

运行以上的测试代码就会发现,程序崩溃了:

除了最后一组,输出的全是随机值,为什么会出现这个问题?

通过以下的代码发现是返回时调用了拷贝构造导致的问题:

myvector::vector<vector<int>> generate(int numRows) {
	myvector::vector<vector<int>> vv;
	//初始化vv前numRows
	vv.resize(numRows);
	//
	for (int i = 0; i < numRows; ++i)
	{
		vv[i].resize(i + 1, 0);
		vv[i][0] = vv[i][vv[i].size() - 1] = 1;
	}
	for (int i = 0; i < vv.size(); ++i)
	{
		for (int j = 0; j < vv[i].size(); ++j)
		{
			if (vv[i][j] == 0)
			{
				vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
			}
		}
	}

	for (int i = 0; i < vv.size(); ++i)
	{
		for (int j = 0; j < vv[i].size(); ++j)
		{
			cout << vv[i][j];
		}
		cout << endl;
	}
	cout << endl;
	return vv;
}

void test5()
{
	myvector::vector<vector<int>> vv = generate(5);
	for (int i = 0; i < vv.size(); ++i)
	{
		for (int j = 0; j < vv[i].size(); ++j)
		{
			cout << vv[i][j];
		}
		cout << endl;
	}
}

再进行更深层的调试后发现,在最后一次即第五行处扩容时出现了问题:

//扩容
		void reserve(size_t n)
		{
			//先将结果保留,因为_start会被更改
			size_t oldsize = size();

			if (n > capacity())
			{
				T* temp = new T[n];
				//_start为空指针时不应该释放
				if (_start)
				{
					memcpy(temp, _start, sizeof(T) * oldsize);
					delete[] _start;
				}
				_start = temp;
				_finish = _start + oldsize;
				_endofstorage = _start + n;
			}
		}

 由于使用了memcpy,所以是浅拷贝,只是把vector的vector里存放数据的地址拷贝到了temp,当delete[] _start,把vector和vector都是释放了,即把数据的那块地址也释放了:

那么,vector的前四个指向之前数据的指针就变成了野指针了,故前四组数据打印的是随机值了,而第五组数据由于没有被释放,自然也就能正常打印了。

因此,这里的扩容函数里的拷贝不应该使用memcpy,使用下面的扩容方式发现可以解决该问题:

//扩容
		void reserve(size_t n)
		{
			//先将结果保留,因为_start会被更改
			size_t oldsize = size();

			if (n > capacity())
			{
				T* temp = new T[n];
				//_start为空指针时不应该释放
				if (_start)
				{
					//该扩容方式是浅拷贝,参数为vector/string容易出现深浅拷贝问题
					/*memcpy(temp, _start, sizeof(T) * oldsize);*/
					for (size_t i = 0; i < size(); ++i)
					{
						//赋值是深拷贝
						temp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = temp;
				_finish = _start + oldsize;
				_endofstorage = _start + n;
			}
		}

总结:

vector<T>中,当T是涉及深浅拷贝的类型时,如:string/vector<T>等等,我们扩容使用memcpy拷贝数据是存在浅拷贝问题的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hiland.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值