views:

314

answers:

9

In a C++ program I write:

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

this program prints the correct value of a[0] (because it is allocated) but also prints values at the rest of the 10 locations instead of giving a segmentation fault.

How to overcome this while writing your code? This causes problems when your code computes something and happily accesses memory not meant to be accessed.

+10  A: 

When you call resize() the vector implementation reallocates the buffer to the size enough to store the requested number of elements - it can't be less than you require but the implementation is free to make it larger to reduce memory fragmentation and make reallocations less often.

The only way to avoid such errors is to only loop within a valid range of indices in your code. For the code you provided the following would do:

for ( int i = 0 ; i < a.size(); i++ ) {
    cout << a[i] << " ";
}
sharptooth
right you are, sir!
Here Be Wolves
A: 

Check the size you are allocating for the vector

gonzohunter
A: 

Over come this problem by being more conscientious while accessing memory: Check for bounds!

Here Be Wolves
+13  A: 

Use this:

a.at(i)

at() will throw an out_of_range exception if the index is out of bounds.

The reason that operator [] doesn't do a bounds check is efficiency. You probably want to be in the habit of using at() to index into a vector unless you have good reason not to in a particular case.

KayEss
ok will keep it in mind ... thanks
balkrishna
That's a way to workaround the incorrectly written code. You could instead just write code correctly - either using size() or iterators.
sharptooth
In an ideal world of course we would always write code correctly -- and personally I don't think that I ever use the vector indexing operators at all.However, using `at()` in non-performance critical code (which is probably most places) is a good "belt and braces"/"defensive coding" thing to do, especially for somewhat inexperienced coders.
KayEss
Disagree. Inexperienced coders should be reviewed, not put in a padded cell.
MSalters
All coders should be reviewed.
KayEss
A: 

I cannot comment yet, but resize() is not a hint for memory allocation. According to the STL documentation, resize(n) inserts or removes elements at the end of the vector. So after calling resize(1), the vector contains exactly 1 element. To allocate memory in advance, you have to call reserve(n).

jopa
+5  A: 

You can avoid the problem completely by using iterators. The for loop would then look something like

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

The segmentation fault happens because the hardware (Memory Management Unit) reconizes that you do not have access to the region, and so it throws a exception. The OS gets that exception and decides what to do about it; in those cases, it realizes you are making an illegal access and kills your application with a segmentation fault.

The same mechanism is how swap is implemented; the OS might reconize that you do have access to the memory, but that it's on the disk right now. Then it brings in the memory from disk and allows your program to continue.

However, this whole memory protection scheme only has enough resolution for pages of memory, e.g., 4k at a time. So the MMU can't protect you from every little overrun you might do. There are tools like ElectricFences that replace malloc and free and take advantage of the MMU, but those are intended only for "spot-checks"... they are good for debugging, but you wouldn't want to run that way forever.

Chris Arguin
+2  A: 

This isn't a memory allocation question per se, it is a bounds checking question. If the memory you overrun (either reading or writing) is still within the legal bounds of the program, you will not segfault.

In the past I've seen an overloaded [ operator that does bounds checking. It was a lot of work to turn C++ into ForTran (one of the better features of ForTran, I might add).

Besides using vectors and iterators, the best answer is to use good programming technique.

kmarsh
A: 

Access to elements outside the bounds of the allocated object results in undefined behavior. That means that the implementation is free to any thing that occurs to it. It might throw and exception if you are very lucky. If you are very unlucky, it will simply appear to work.

It is permitted, in principle, for it to cause demons to fly out of your nose.

Its behavior is undefined.

RBerteig