• vector实现——memcpy拷贝问题


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

    1. myvector::vectorint>> generate(int numRows) {
    2. myvector::vectorint>> vv;
    3. //初始化vv前numRows
    4. vv.resize(numRows);
    5. //
    6. for (int i = 0; i < numRows; ++i)
    7. {
    8. vv[i].resize(i + 1, 0);
    9. vv[i][0] = vv[i][vv[i].size() - 1] = 1;
    10. }
    11. for (int i = 0; i < vv.size(); ++i)
    12. {
    13. for (int j = 0; j < vv[i].size(); ++j)
    14. {
    15. if (vv[i][j] == 0)
    16. {
    17. vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
    18. }
    19. }
    20. }
    21. return vv;
    22. }
    23. void test5()
    24. {
    25. myvector::vectorint>> vv = generate(5);
    26. for (int i = 0; i < vv.size(); ++i)
    27. {
    28. for (int j = 0; j < vv[i].size(); ++j)
    29. {
    30. cout << vv[i][j];
    31. }
    32. cout << endl;
    33. }
    34. }

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

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

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

    1. myvector::vectorint>> generate(int numRows) {
    2. myvector::vectorint>> vv;
    3. //初始化vv前numRows
    4. vv.resize(numRows);
    5. //
    6. for (int i = 0; i < numRows; ++i)
    7. {
    8. vv[i].resize(i + 1, 0);
    9. vv[i][0] = vv[i][vv[i].size() - 1] = 1;
    10. }
    11. for (int i = 0; i < vv.size(); ++i)
    12. {
    13. for (int j = 0; j < vv[i].size(); ++j)
    14. {
    15. if (vv[i][j] == 0)
    16. {
    17. vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
    18. }
    19. }
    20. }
    21. for (int i = 0; i < vv.size(); ++i)
    22. {
    23. for (int j = 0; j < vv[i].size(); ++j)
    24. {
    25. cout << vv[i][j];
    26. }
    27. cout << endl;
    28. }
    29. cout << endl;
    30. return vv;
    31. }
    32. void test5()
    33. {
    34. myvector::vectorint>> vv = generate(5);
    35. for (int i = 0; i < vv.size(); ++i)
    36. {
    37. for (int j = 0; j < vv[i].size(); ++j)
    38. {
    39. cout << vv[i][j];
    40. }
    41. cout << endl;
    42. }
    43. }

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

    1. //扩容
    2. void reserve(size_t n)
    3. {
    4. //先将结果保留,因为_start会被更改
    5. size_t oldsize = size();
    6. if (n > capacity())
    7. {
    8. T* temp = new T[n];
    9. //_start为空指针时不应该释放
    10. if (_start)
    11. {
    12. memcpy(temp, _start, sizeof(T) * oldsize);
    13. delete[] _start;
    14. }
    15. _start = temp;
    16. _finish = _start + oldsize;
    17. _endofstorage = _start + n;
    18. }
    19. }

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

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

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

    1. //扩容
    2. void reserve(size_t n)
    3. {
    4. //先将结果保留,因为_start会被更改
    5. size_t oldsize = size();
    6. if (n > capacity())
    7. {
    8. T* temp = new T[n];
    9. //_start为空指针时不应该释放
    10. if (_start)
    11. {
    12. //该扩容方式是浅拷贝,参数为vector/string容易出现深浅拷贝问题
    13. /*memcpy(temp, _start, sizeof(T) * oldsize);*/
    14. for (size_t i = 0; i < size(); ++i)
    15. {
    16. //赋值是深拷贝
    17. temp[i] = _start[i];
    18. }
    19. delete[] _start;
    20. }
    21. _start = temp;
    22. _finish = _start + oldsize;
    23. _endofstorage = _start + n;
    24. }
    25. }

    总结:

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

  • 相关阅读:
    linux中利用VScode编写python程序
    Java的IO流-转换流
    Android GridLayoutManager Glide批量加载Bitmap绘制Canvas画在RecyclerView,Kotlin(a)
    【PHP】php中JSON或数组到formData的键值对转换
    java SE 基础
    选择排序超详细讲解C语言
    云IDE开发产品
    【4003】基于springboot实现的线上阅读系统
    JMeter 设置请求头信息的详细步骤
    pycharm+selenium+edge环境配置
  • 原文地址:https://blog.csdn.net/Britney_dark/article/details/126940889