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

时间:2009-06-11 11:49:08

标签: c++ memory-management stl

在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;
}

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

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

9 个答案:

答案 0 :(得分:13)

使用此:

a.at(i)
如果索引超出范围,

at()将抛出out_of_range异常。

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

答案 1 :(得分:10)

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

避免此类错误的唯一方法是仅在代码中的有效索引范围内循环。对于您提供的代码,可以执行以下操作:

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

答案 2 :(得分:5)

您可以使用迭代器完全避免此问题。 for循环看起来像

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

答案 3 :(得分:2)

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

过去我见过一个重载的[运算符,它确定了边界检查。将C ++变成ForTran是很多工作(ForTran的一个更好的功能,我可能会添加)。

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

答案 4 :(得分:0)

检查您为矢量分配的大小

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我还不能评论,但resize()不是内存分配的提示。 根据{{​​3}},resize(n)在向量的末尾插入或删除元素。因此在调用resize(1)之后,向量恰好包含1个元素。 要提前分配内存,您必须调用reserve(n)。

答案 7 :(得分:0)

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

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

然而,这整个存储器保护方案仅对存储器页面具有足够的分辨率,例如,每次4k。因此,MMU无法保护您免受可能发生的每一次超限。像ElectricFences这样的工具可以替代malloc和free并利用MMU,但这些工具仅用于“抽查”......它们适合调试,但你不想永远以这种方式运行。 / p>

答案 8 :(得分:0)

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

原则上允许它使恶魔飞出你的鼻子。

其行为未定义