【问题标题】:How to demonstrate memory error using arrays in C++如何在 C++ 中使用数组演示内存错误
【发布时间】:2011-02-16 02:58:29
【问题描述】:

我试图想出一种方法来演示一种使用数组和 C++ 的内存错误,这很难检测到。目的是鼓励 STL 向量 与迭代器结合使用。

编辑:接受的答案是我用来解释优点/缺点的答案。我也用过:this

【问题讨论】:

  • 大多数此类错误很难检测 - 如果它们很容易,就不会有这样的问题。
  • 内存错误通常是一种未定义行为。因此,该程序可以做任何事情,包括看起来正常工作。在尝试此操作时,您可能希望尽可能提高编译器优化。这通常会使代码对这些类型的问题更加敏感。
  • 开启on 编译器优化...呃,最初我认为它会反过来。谢谢。

标签: c++ memory-leaks arrays


【解决方案1】:

new/delete 和 new[]/delete[] 配对不当。

例如,使用:

int *array = new int[5];
delete array;

代替:

int *array = new int[5];
delete [] array;

虽然 c++ 标准不允许这样做,但一些编译器支持堆栈分配数组:

int stack_allocated_buffer[size_at_runtime];

这可能是范围规则的意外副作用(例如,被成员变量遮蔽的常量)......并且它一直有效,直到有人传递 'size_at_runtime' 太大并炸毁堆栈。然后会出现蹩脚的错误。

【讨论】:

  • @avakar:C++ 可能没有它们,但一些编译器(例如 gcc)将它们作为扩展提供。
  • @Stephen:在某个编译器上工作几乎不涉及代码的合规性。 VLA 仅适用于 C99,而非 C++。第一部分 +1,第二部分 -1,来自我。 @Bill:问题不是关于 C++ 的特定编译器实现,而是关于 C++。
  • @GMan,不幸的是,错误不会检查标准合规性。几年前,我发现这是一个非常真实的错误 :( 至少在 g++ 上。
  • @Bill:我们错过了问题中提到“跨平台错误”的部分。 :)
  • @all:编辑答案中的语言以反映标准一致性。感谢您的反馈。对于那些认为这不能回答问题的人......问题是关于避免真正的错误......不是标准合规性,不是最佳实践,也不是跨平台代码。我被咬过,所以我认为它是有效的。 :)
【解决方案2】:

内存泄漏? IMO,向量与迭代器结合并不能特别保护您免受错误的影响,例如超出范围或通常使用无效的迭代器(除非您有带有迭代器调试的 VC++);相反,它很方便,因为它为您实现了一个可动态调整大小的数组并负责内存管理(注意!有助于使您的代码更加安全)。

void foo(const char* zzz)
{
    int* arr = new int[size];
    std::string s = zzz;
    //...
    delete[] arr;
}

如果发生异常(例如在创建字符串时),上述内容可能会泄漏。不是向量。

由于其值语义,Vector 还可以更轻松地对代码进行推理。

int* arr = new int[size];
int* second_ref = arr;
//...
delete [] arr; 
arr = 0; //play it safe :)

//...
second_ref[x] = y;
//...
delete [] second_ref;

但也许向量不会自动满足 100% 的动态数组用例。 (比如还有boost::shared_array和未来的std::unique_ptr<T[]>

【讨论】:

  • VC++ 并不是唯一具有迭代器调试功能的 C++ 库。 STLPort 也有,使用-D_GLIBCXX_DEBUG 编译时,libstdc++(GNU C++ 库)也有。
  • @Ken:感谢您通知我。 (我个人在选择vector时并没有考虑安全性,我选择它是因为它只是为我做事。)
【解决方案3】:

我认为当您需要动态数组时,std::vector 的实用性真正体现出来了。

使用 std::vector 做一个例子。然后是一个使用数组重新分配的示例。我认为它不言自明。

【讨论】:

    【解决方案4】:

    一个明显的:

    for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
        destination_array[i] = whatever(i);
    

    for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
        destination_vector.push_back(whatever(i));
    

    指出您知道第二个有效,但第一个是否有效取决于destination_array 的定义方式。

    【讨论】:

      【解决方案5】:
      void Fn()
      {
          int *p = new int[256];
          if ( p != NULL )
          {
              if ( !InitIntArray( p, 256 ) )
              {
                    // Log error
                    return;
              }
              delete[] p;
          }
      }
      

      你不会相信我经常看到这种情况。任何形式的 RAII 都有用的经典示例...

      【讨论】:

        【解决方案6】:

        我认为使用vectors 代替动态数组的基本简单性已经令人信服。

        1. 您不必记住删除您的记忆...这并不简单,因为尝试删除它可能会被异常等绕过。
        2. 如果你想自己做动态数组,在 C++ 中最安全的方法是将它们包装在一个类中并使用RAII。但是向量会为您做到这一点。实际上,这就是重点。
        3. 已为您调整大小。
        4. 如果您需要支持任意类型,您无需做任何额外的工作。
        5. 提供了许多算法,旨在处理容器,包括其他用户和其他用户。
        6. 如果需要,您仍然可以通过传递向量的底层数组来使用需要数组的函数;标准保证内存是连续的,vector&lt;bool&gt; 除外(谷歌表示截至 2003 年,请参阅规范的 23.2.4./1)。
        7. 一般来说,自己使用数组可能是不好的做法,因为您将成为re-inventing the wheel...而且您的实现几乎肯定会比现有的更糟糕...而且其他人更难使用,因为他们知道vector,但不知道你的怪事。

        使用动态数组,您需要自己跟踪大小,在您想要插入新元素时增加它,在不再需要它时删除它......这是额外的工作。 哦,还有一个警告:vector&lt;bool&gt; 是一个肮脏的烂黑客和过早优化的经典示例。

        【讨论】:

          【解决方案7】:

          你为什么不根据 STL 提供的算法来激励它?

          【讨论】:

          • STL 也为数组提供了所有相同的算法。 - 但是,是的,最大的动力应该是向量 为你做事,否则你会自己编写的东西(除非你很了解 C++,否则不会只知道如何高效地实现,例如调整大小)。
          • 除了所有(或至少几乎所有)适用于std::vector 的 STL 算法也适用于使用指向数组的指针作为迭代器的原始数组。
          • @Tyler:我认为 all 因为它们属于同一个迭代器类别。
          • @Tyler:要做到这一点,您必须将原始数组视为迭代器。通常在 C 中,你传入一个数组a 和一个大小n。在 STL 中,您传入一个指向起始元素的指针(即数组指针 a)和一个过去的指针(a+n)。从那里开始,这是向vector&lt;something&gt; 及其begin()end() 成员迈出的一小步,您可以通过它现在可以与std::liststd::deque 互换(至少大部分)这一事实来进一步激励它。
          【解决方案8】:

          在原始数组中,operator[](如果我可以这样称呼的话)容易受到索引越界问题的影响。使用矢量则不是(至少有一个运行时异常)。

          对不起,我没有仔细阅读这个问题。 index-out-of-bound 是个问题,但不是内存错误。

          【讨论】:

          • 向量中的运算符[] 检查边界;而是由 at 方法执行检查。
          猜你喜欢
          • 1970-01-01
          • 2011-12-12
          • 1970-01-01
          • 2018-10-04
          • 2017-01-04
          • 2012-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多