克服 C++ 中的错误内存分配

Posted

技术标签:

【中文标题】克服 C++ 中的错误内存分配【英文标题】:Overcoming wrong memory allocation in C++ 【发布时间】:2009-06-11 11:49:07 【问题描述】:

在我编写的 C++ 程序中:

#include<iostream>
#include<vector>
using namespace std;
int main()

   vector<int> a;
   a.resize(1); 
   for( int i = 0 ; i < 10 ; i++ ) 
       cout << a[i] << " ";
   

   return 0;

此程序打印 a[0] 的正确值(因为它已分配),但也打印其余 10 个位置的值,而不是给出分段错误。

在编写代码时如何克服这个问题?当您的代码计算某些东西并愉快地访问不打算访问的内存时,这会导致问题。

【问题讨论】:

这里实际上并没有打印这些值 - 编译器在实现未定义行为方面有所不同。 我用的是 GNU 编译器.....你用的是哪一个 【参考方案1】:

使用这个:

a.at(i)

如果索引超出范围,at() 将抛出 out_of_range 异常。

operator [] 不做边界检查的原因是效率。您可能希望养成使用at() 来索引向量的习惯,除非您有充分的理由在特定情况下不这样做。

【讨论】:

这是一种解决错误编写代码的方法。您可以改为正确编写代码 - 使用 size() 或迭代器。 当然,在理想的世界中,我们总是会正确编写代码——而且我个人认为我根本没有使用过向量索引运算符。但是,在非性能关键代码(可能是大多数地方)中使用at() 是一个很好的“安全带和大括号”/“防御性编码”的事情,特别是对于有些缺乏经验的编码人员。 不同意。应该审查没有经验的编码人员,而不是放在填充单元格中。【参考方案2】:

当您调用 resize() 时,向量实现会将缓冲区重新分配到 足够 的大小以存储请求的元素数量 - 它不能小于您的要求,但实现是免费的它更大以减少内存碎片并减少重新分配的频率。

避免此类错误的唯一方法是仅在代码的有效索引范围内循环。对于您提供的代码,如下所示:

for ( int i = 0 ; i < a.size(); i++ ) 
    cout << a[i] << " ";

【讨论】:

【参考方案3】:

使用迭代器可以完全避免这个问题。然后 for 循环看起来像

for(vector<int>::iterator i = a.begin(); i != a.end(); ++i)
    cout << *i << " ";

【讨论】:

【参考方案4】:

这本身不是内存分配问题,而是边界检查问题。如果您超出的内存(读取或写入)仍在程序的合法范围内,则不会出现段错误。

在过去,我见过一个重载的 [ 进行边界检查的运算符。将 C++ 转换为 ForTran(我可能会补充说,这是 ForTran 的一个更好的特性)需要做很多工作。

除了使用向量和迭代器,最好的答案是使用好的编程技术。

【讨论】:

【参考方案5】:

检查您为向量分配的大小

【讨论】:

【参考方案6】:

通过在访问内存时更加认真来解决这个问题:检查边界!

【讨论】:

【参考方案7】:

我还不能评论,但是 resize() 不是内存分配的提示。 根据STL documentation,resize(n) 在向量末尾插入或删除元素。所以在调用 resize(1) 之后,向量正好包含 1 个元素。 要提前分配内存,必须调用reserve(n)。

【讨论】:

【参考方案8】:

发生分段错误是因为硬件(内存管理单元)重新确认您无权访问该区域,因此它会引发异常。操作系统收到该异常并决定如何处理它;在这些情况下,它会意识到您正在进行非法访问,并因分段错误而终止您的应用程序。

相同的机制是如何实现交换;操作系统可能会重新确认您确实可以访问内存,但它现在在磁盘上。然后它会从磁盘中调入内存并允许您的程序继续运行。

但是,整个内存保护方案仅对内存页面具有足够的分辨率,例如一次 4k。所以 MMU 不能保护你免受你可能做的每一个小超支。有诸如 ElectricFences 之类的工具可以替代 malloc 和 free 并利用 MMU,但这些工具仅用于“抽查”……它们非常适合调试,但您不想永远那样运行。

【讨论】:

【参考方案9】:

访问分配对象边界之外的元素会导致未定义的行为。这意味着实现对它发生的任何事情都是免费的。如果你很幸运,它可能会抛出异常。如果你很不走运,它只会看起来有效。

原则上,它可以让恶魔从你的鼻子里飞出来。

它的行为是未定义

【讨论】:

以上是关于克服 C++ 中的错误内存分配的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中的 2D 动态内存分配数组中释放分配的内存

C++中内存分配问题

C# 中锯齿状数组的内存分配与 C++ 中的二维数组内存分配

小白学习C++ 教程十六C++ 中的动态内存分配

挣扎 - 又一个内存损坏问题,错误分配(C++,VS 2008)

什么是 C++ 中的动态内存分配?