I am trying to use a standard exception class in c++ like:
#include <iostream>
#include <exception>
using namespace std;
int main(){
int a[6]={12,3,2,4,5,6};
int n=6;
try{
cout<<a[6]<<" ";
}
catch(std::exception & exc)
{
cout<<exc.what();
}
return 0;
}
But instead of showing me the error - "out of index" ,it throws a run time error, saying that the "variable a is uninitialized" ,why? I have declared it as an array and make initialization of it. Please give me some advise why it does so?
Accessing a[6] is undefined behaviour, since the only valid indices for a are 0..5.
You shouldn't expect a[6] to perform any bounds checking, much less throw a C++ exception on out-of-bounds array access.
If do you want automatic bounds checking, make a into std::vector<int> and use a.at(index) to access its elements.
A standard array does not check the bounds of your access. If you want a bound checking array you'd either use boost/std::array or std::vector and use the bound safe access function at().
You've declared a to be an array of six elements; the legal indexes run from 0 to 5. The result of the expression a[6] is undefined behavior -- program termination is (in this case) the result. Nowhere does it say that illegal array access will throw an exception -- this is not Java!
c++ does not check array sizes, so there is no exception thrown. If you want this check, you have to use a STL container like std::vector.
C++ exceptions are not meant to be used to catch programming errors. They are there for run time errors like unable to open a file etc.
Related
I have a large code I'm trying to integrate into an existing program. For this, I need to work with c++ 2d and 1d arrays. I'm most familiar with python; if I tried
import numpy as np
x = np.zeros(10)
x[20] = 3
print(x[15])
Both lines 3 and 4 would cause an error to occur. In c++, this doesn't cause an error, instead a segfault will likely occur somewhere in the code (or the computed answer is meaningless). My question is, how can I ensure memory assignment/access in a c++ array is correct? Are the compiler options or debugging tools that would help with this? I am using g++ to compile the code.
With raw arrays, there is no way except if you keep track of the actual size yourself.
In C++, you only pay for what you use. In other words, the bounds checking is up to the developer to implement so that it won't penalize someone who does not actually need it.
A good practice is to not use raw arrays but use standard containers instead (std::array, std::vector, ...). They own their data and keep track of the size for you.
With standard containers, there is an at() member function that throws an std::out_of_range exception if you try to access an out of bounds index.
On the other hand, if you don't want to handle the exception, you still can do the bounds checking manually using the size() member function.
One valid implementation of your example bay be:
std::vector<int> x(10, 0); // Vector of 10 elements initialized with value 0
Bounds checking with exception handling:
try
{
x.at(12) = 3; // at()
}
catch(std::exception & e)
{
std::cout << e.what() << std::endl;
}
Manual bounds checking:
if(12 < x.size())
x[12] = 3; // operator[]
Note: std::vector requires to #include <vector> and std::array requires to #include <array>.
The compiler will warn you if you use a literal index like shown in your question:
#include <stdio.h>
int main() {
int thing[2] = {0};
printf("%d", thing[3]);
return 0;
}
test.cpp:5:15: warning: array index 3 is past the end of the array (which contains 2 elements) [-Warray-bounds]
printf("%d", thing[3]);
^ ~
test.cpp:4:2: note: array 'thing' declared here
int thing[2] = {0};
^
1 warning generated.
It will not, however, generate an error if you use a variable to index into the array, and the value of that variable is out-of-range. For example:
#include <stdio.h>
int main() {
int thing[2] = {0};
int index = 3;
printf("%d", thing[index]);
return 0;
}
The behaviour here is undefined, and the compiler won't let you know. The best you can do in these cases is put a check in place before the array access.
This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 7 years ago.
Why this:
#include <iostream>
using namespace std;
int main() {
int a[1] = {0};
a[2048] = 1234;
cout << a[2048] << endl;
return 0;
}
does not give any compile-time error? (gcc 4.9.3)
Because this is legal C++.
You can try to dereference any pointer, even if it's not allocated by your program, you can try to access any cell of an array, even if it is out of bounds, the legality of an expression doesn't depend on the values of the variables involved in that expression.
The compiler doesn't have to run any static analysis to check whether you'll actually cause undefined behaviour or not, and shouldn't fail to compile if it assumes that you will (even when it is obvious that you will).
The problem is that you can't check all possible array access at compile-time (that would be way too expensive), so you'd have to arbitrarily draw a line somewhere (the problem being the word "arbitrarily", that wouldn't fit well in the standard).
Hence, checking that you won't cause undefined behaviour is the responsability of the programmer (or of specific static analysis tools).
Access to out of array range does not give any error
This is just because you were unlucky. :) What you can call it is "Undefined Behavior". Compiler is not doing any bound check on arrays, and what you are trying to do in statement a[2048] = 1234;is to write a memory location on stack, which is unused.
I have a couple of questions concerning C++ exceptions. For reference, I am learning C++ through Bjarne Stroustrup's "Programming Principles and Practice using C++".
My first questions I think is simple: around page 147, we are talking about exceptions dealing with referencing an index outside of the range of a vector. So his try catch block is
int main(){
try{
vector<int> v;
int x;
while(cin>>x)
v.push_back(x);
for(int i = 0; i<=v.size();i++)
cout<<"v["<<i<<"] == "<<v[i]<<endl;
} catch (out_of_range_error){
cerr<<"Oops! Range error\n"
return 1;
} catch(...){
cerr<<"Exception: something went wrong\n";
return 2;
}
}
So my question is what is out_of_range_error ?! Early on in the book he mentions the use of a header file to use so new people need not concern themselves with nuances. That file is located here
but out_of_range_error is no where there. Just the standard out_of_range exception you can check for normally (after importing stdexcept). And even when I use that file (which I normally don't) the compiler (g++) tells me it expects an identifier for out_of_range_error. So is this just some typo in this mass-produced book? Or am I missing something?
My second question is on the same topic, if I don't import the file he gives, but instead just do:
#include <iostream>
#include <stdexcept>
#include <vector>
using namespace std;
/*
#include "std_lib_facilities.h"
*/
int main()
{
try
{
vector<int> newVec;
int x;
while(cin>>x)
newVec.push_back(x);
for(int i = 0; i<=newVec.size()+200;i++)
cout<<newVec[i]<<endl;
return 0;
}//try
catch (out_of_range)
{
cerr<<"runtime error: "<<endl;
return 1;
}//catch
}//main()
then my code runs with no call to the catch block, even though I reference newVec[newVec.size()+200] in the end. It just returns a bunch of 0s with other integers randomly strewn about. I expect these are just the next bits of memory that would have been allocated for newVec, Vector is not special here, the same thing happens with arrays.
So why does C++ not do any range checking? Or does it do range checking and just not care?
If I use
vector<int> v(10);
v.at(20) = 100;
then I get an error, but if I just want to reference, or assign to, v[20] I get no problems. Why is this?
Is this common in C++? Do you often need extra code to FORCE C++ to notice array bounds? This seems very hazardous, coming from a java background. Java would immediately alert you to any indexing errors, but C++ seems content to let you carry on with incorrect logic.
Thanks so much for any responses, sorry for a long-winded attempt at asking this question.
Relative to your first question then I am sure that out_of_range_error is a typo. There should be out_of_range(See section 19.4 of the book for additional information).
As for the second question then operator [] for vectors does not throw the exception std::out_of_range it simulates the bahaviour of arrays. So there is simply undefined behaviour. If you want that there would be a check of the range then you have to use member function at
By the way if the book has errate at the site then you should look through it.
One of the most important principles motivating the design of C++ and its standard library is "you don't pay for what you don't need".
Properly written code shouldn't be accessing array (or vector) out of bounds, therefore they don't need bounds checking, and therefore they shouldn't be forced to pay for it. Bounds checking can easily double the cost of an array access. Similar designs can be seen throughout the C++ standard library - for example, std::lock_guard vs. std::unique_lock, std::condition_variable vs. std::condition_variable_any. In each case the latter class adds extra functionality at extra cost, so users who don't need the extra functionality could simply use the more lightweight version.
If you do need bounds checking, then std::vector provides the member function at() for this purpose.
In this code below I try to access the '-1'th element of an array, I don't get any runtime error.
#include <stdio.h>
int A[10] = {0};
int main(){
A[-1] += 12;
printf("%d",A[-1]);
return 0;
}
When I run the code, it outputs 12 that means it is adding 12 to the non-existent A[-1]. Till today whenever I had tried to access an out-of-bounds element, I had got a runtime-error. I had never tried it on a simple code before.
Can anyone explain why does my code run successfully?
I ran it on my computer and also on ideone, in both the cases it ran successfully.
You see, when you allocate a variable like this, it lands on the stack. Stack holds small packages of information about local variables in each function you call, to say it in simple words. The runtime is able to check, whether you exceed the bounds of allocated stack, but not if you write some data in the invalid place on the stack. The stack may look like the following:
[4 bytes - some ptr][4 bytes - A's first element][4 bytes - A's second element] ...
When you try to assign to -1th element of an array, you actually attempt to read four bytes preceding the array (four bytes, because it's an int array). You overwrite some data held on stack - but that's still in valid process's memory, so there are no complaints from the system.
Try running this code in release mode in Visual Studio:
#include <stdio.h>
int main(int argc, char * argv[])
{
// NEVER DO IT ON PURPOSE!
int i = 0;
int A[5];
A[-1] = 42;
printf("%d\n", i);
getchar();
return 0;
}
Edit: in response to comments.
I missed the fact, that A is global. It won't be held in stack, but instead (mostly probably) in .data segment of the binary module, however the rest of explanation stands: A[-1] is still within process's memory, so assignment won't raise AV. However, such assignment will overwrite something, that is before A (possibly a pointer or other part of the binary module) resulting in undefined behavior.
Note, that my example may work and may not, depending on compiler (or compiler mode). For example, in debug mode the program returns 0 - I guess, that memory manager inserts some sentry data between stack frames to catch errors like buffer over/underrun.
C and C++ does not have any bounds checking. It is a part of the language. It is to enable the language to execute faster.
If you want bounds checking use another language that has it. Java perhaps?
As your code executes you are just lucky.
In C++ (and C), the arrays don't check out of range indices. They're not classes.
In C++11, however you could use std::array<int,10> and at() function as:
std::array<int,10> arr;
arr.at(-1) = 100; //it throws std::out_of_range exception
Or you can use std::vector<int> and at() member function.
Why the array is not overflowed (e.g. error alert) when the array is declared globally, in other why I'm able to fill it with unlimited amount of elements (through for) even it's limited by size in declaration and it does alert when I declare the array locally inside the main ?
char name[9];
int main(){
int i;
for( int i=0; i<18; ++i){
cin>>name[i];
}
cout<<"Inside the array: ";
for(i=0; i<20; i++)
cout<<name[i];
return 0;
}
C++ does not check bounds errors for arrays of any kind. Reading or writing outside of the array bounds causes what is known as "undefined behaviour", which means anything could happen. In your case, it seems that what happens is that it appears to work, but the program will still be in an invalid state.
If you want bounds checking, use a std::vector and its at() member function:
vector <int> a( 3 ); // vector of 3 ints
int n = a.at( 0 ); // ok
n = a.at( 42 ); // throws an exception
C++ does not have array bounds checking so the language never check to see if you have exceeded the end of your array but as others have mentioned bad things can be expected to happen.
Global variables exists in the static segment which is totally separate from your stack. It also does not contain important information like return addresses. When you exceed an array's boundaries you are effectively corrupting memory. It just so happens that corrupting the stack is more likely to cause more visible bad things than corrupting the data segment. All of this depends on the way your operating system organizes a process's memory.
its undefined behavior. Anything can happen.
You cannot assume too much about the memory layout of variables. It may run on your computer with these parameters, but totally fail when you increase your access bounds, or run that code on another machine. So if you seriously want to write code, don't let this become a habit.
I'd go one step further and state that C/C++ do not have arrays. What they have is array-like syntactic sugar that is immediately translated to pointer arithmetic, which cannot be checked, as pointers can be used to access potentially all of memory. Any checking that the compiler may manage to perform based on static sizes and constant bounds on an index is a happy accident, but you cannot rely on it.
Here's an oddity that stunned me when I first saw it:
int a[10], i;
i = 5;
a[i] = 42; // Looks normal.
5[a] = 37; // But what's this???
std::cout << "Array element = " << a[i] << std::endl;
But the odd-looking line is perfectly legal C++. This example emphasizes that arrays in C/C++ are a fiction.
Neil Butterworth already commented on the benefits of using std::vector and the at() access method for it, and I cannot second his recommendation strongly enough. (Unfortunately, the designers of STL blew a golden opportunity to make checked access the [] operators, with the at() methods the unchecked operators. This has probably cost the C++ programming community millions of hours and millions of dollars, and will continue to do so.)