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拷贝数据是存在浅拷贝问题的。