vector实现完了函数,但是在进行测试时发现,如果使用自己的vector来完成一个杨辉三角的题目出现了问题:
- myvector::vector
int>> generate(int numRows) { - myvector::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
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
int>> generate(int numRows) { - myvector::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
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