在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个位置的其余位置打印值,而不是给出分段错误。
如何在编写代码时克服这个问题?当您的代码计算某些内容并愉快地访问无意访问的内存时,这会导致问题。
答案 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)
访问分配对象边界之外的元素会导致未定义的行为。这意味着实现对于发生的任何事情都是免费的。如果你很幸运,它可能会抛出异常。如果你非常不走运,它似乎会起作用。
原则上允许它使恶魔飞出你的鼻子。
其行为未定义。