2

I'm a absolute beginner for programming. I got this error while building up the following code.

error: terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 8) >= this->size() (which is 8) Aborted (core dumped)

#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
using namespace std;
int main()
{
    cout<<"\n Welcome to space travel calculation program";

    string cPlanet, name;
    double weight, speed, tTime, nWeight;
    int num;
    vector<string> planet;
    vector<int> distance;
    vector<double> sGravity;

    planet.push_back("Mercury");
    distance.push_back(36);
    sGravity.push_back(0.27);

    planet.push_back("Venus");
    distance.push_back(67);
    sGravity.push_back(0.86);

    planet.push_back("Earth");
    distance.push_back(93);
    sGravity.push_back(1.00);

    planet.push_back("Mars");
    distance.push_back(141);
    sGravity.push_back(0.37);

    planet.push_back("Jupiter");
    distance.push_back(483);
    sGravity.push_back(2.64);

    planet.push_back("Saturn");
    distance.push_back(886);
    sGravity.push_back(1.17);

    planet.push_back("Uranus");
    distance.push_back(1782);
    sGravity.push_back(0.92);

    planet.push_back("Neptune");
    distance.push_back(2793);
    sGravity.push_back(1.44);
    num=planet.size();

    cout<<"\n Please tell me your name: ";
    getline(cin,name);


    cout<<"\n Please choose which planet you want to travel to from the following list:"
        <<"\n 1.Mercury"
        <<"\n 2.Venus"
        <<"\n 3.Earth"
        <<"\n 4.Mars"
        <<"\n 5.Jupiter"
        <<"\n 6.Saturn"
        <<"\n 7.Uranus"
        <<"\n 8.Neptune       :";
    getline(cin,cPlanet);

    cout<<"\n What is your weight on Earth?";
    cin>>weight;

    cout<<"\n At what speed do you wish to travel? :";
    cin>>speed;

    if(cPlanet==planet.at(num))
    {
        tTime=(distance.at(num))/speed;
        nWeight=weight*sGravity.at(num);

        cout<<"\n Your Name: "<<name
            <<"\n Weight On Earth: "<<weight
            <<"\n Planet you wish to visit: "<<cPlanet
            <<"\n The speed you will be travelling at: "<<speed
            <<"\n Total time it will take to reach "<<planet.at(num)<<": "<<tTime
            <<"\n Your weight on "<<planet.at(num)<<": "<<nWeight;
    }

    return 0;
}
Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
santosh
  • 107
  • 2
  • 3
  • 6

2 Answers2

4

Array and vector indices in C++ run from 0 to size - 1. Thus when you say

num=planet.size();

and later

if(cPlanet==planet.at(num))

you are trying to access one past the end of the vector planet. The at member function then throws an exception of type std::out_of_range that is never caught, and your program terminates because of that.

It looks as though you wanted to find the vector index corresponding to a planet name; you could do that with std::find and std::distance as follows:

num = std::distance(planet.begin(), std::find(planet.begin(), planet.end(), cPlanet));

this will return planet.size() if cPlanet is not found. However, it would probably be nicer to implement the whole thing with a std::map.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
0

Here's a simpler program to reproduce the behaviour:

#include <vector>

int main()
{
    std::vector<int> v;
    v.push_back(123); // v has 1 element  [0 to 0]
    v.push_back(456); // v has 2 elements [0 to 1]
    v.push_back(789); // v has 3 elements [0 to 2]
    int x1 = v.at(0); // 123
    int x2 = v.at(1); // 456
    int x3 = v.at(2); // 789
    int x4 = v.at(3); // exception
}

The at member function throws an exception if you try to access a non-existing element.

While that principally sounds like a good thing, it turns out to be pretty useless in practice. Using an illegal vector index is almost surely a programming error, and exceptions should not be thrown for programming errors.

You could catch the std::out_of_range exception to "recover" from the error or "handle" it, but seriously, what could you possibly do at such a low level of program logic?

For std::vector, prefer the [] operator. In your case:

tTime = distance[num] / speed;

[] is like at, but takes an entirely different stance on programming errors; at is like "if you should ever call me with an illegal index, I'll throw an exception so that we can somehow carry on, shall we?", whereas with the [] operator the behaviour is undefined for illegal vector indices. This means a C++ implementation is allowed to just terminate the program without any chance of accidentally catching an exception and "continuing somehow". It depends on how you invoke the compiler and generally requires you to examine your compiler's configuration options (for example those for VC++ or those for GCC).

Terminating as quickly as possible is the right thing to do when you find out that your own code is wrong. Do not get used to at's behaviour.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • 1
    In practice, any C++ implementation will usually run past an out-of-bounds access into a vector with `operator[]` and silently do some wrong thing with the data it happens to find in the referenced memory location. It is simply not the case that "any good C++ implementation" will terminate reliably in such cases. – Wintermute Mar 15 '15 at 15:09
  • @Wintermute: Well, you also have to make sure not to remove all those checks when you compile the code. Unless the performance penalty is actually visible. Perhaps a better way to put it would be: "any good C++ implementation allows you to terminate reliably". – Christian Hackl Mar 15 '15 at 15:12
  • @Wintermute Right, I must never have seen such a "good C++ implementation" in all my years as a C++ programmer ;-) I had happily assumed there would be no overhead in `operator[]`. – juanchopanza Mar 15 '15 at 15:13
  • 1
    Among common C++ implementations, such checks exist only in the "safe" version of MSVC's runtime library. Neither gcc's libstdc++ nor clang's libc++ contain such checks in the first place. Relying on their existence is foolhardy. – Wintermute Mar 15 '15 at 15:13
  • @Wintermute: What about `_GLIBCXX_DEBUG`? – Christian Hackl Mar 15 '15 at 15:32
  • Of course, ideally you'd have an `assert` in your own code at an earlier point, before the wrong index has a chance to get into the subscript operator. And error checks in higher layers of your software as well. But I've never seen any use for `at` in any C++ code I've ever written. – Christian Hackl Mar 15 '15 at 15:36
  • `_GLIBCXX_DEBUG` has no influence on `vector::operator[]`. Whether `at` is a sensible replacement is another matter; regardless of it, the claim that `operator[]` will terminate your program reliably when fed out-of-bound indices is false. – Wintermute Mar 15 '15 at 15:36
  • @ChristianHackl The `assert` would most likely not have any effect in production mode because the `NDEBUG` flag would be set. In any case, the standard says out of bounds access with `operator[]` is UB, so implementations are free to implement it without overhead. – juanchopanza Mar 15 '15 at 15:40
  • @juanchopanza: I have the somewhat controversial opinion that you should by default not distinguish between "debug" and "release" builds and that `assert` should only be turned off in those few compilation units where it really matters for performance. Anyway, I'll change my answer text to something less absolute. – Christian Hackl Mar 15 '15 at 16:03
  • @Wintermute: Huh? I'm pretty sure it does. I just tried it with clang online, and got the expected `error: attempt to subscript container with out-of-bounds index 0` at calling `[0]` on an empty vector. I currently have no GCC on this machine, so please elaborate on this. – Christian Hackl Mar 15 '15 at 16:16
  • Ah, libcxx appears to have asserts in there now that can be enabled with `_LIBCPP_DEBUG_LEVEL` (not that anyone actually does that). As for libstdc++, you can see in `/usr/include/c++/version/bits/stl_vector.h` that the `operator[]` implementations contain no checks. Around line 780 for version 4.9. – Wintermute Mar 15 '15 at 16:58
  • @Wintermute: What about https://gcc.gnu.org/onlinedocs/gcc-4.9.1/libstdc++/api/a01591_source.html, line 357, where it calls `__glibcxx_check_subscript`? I am confused, or my brain is too much in weekend mode, or we are talking about different things. – Christian Hackl Mar 15 '15 at 17:06
  • Ah, I never noticed that bit; the gate was in a place where I didn't expect it. That looks good for some debugging purposes, but you'll be hard-pressed to use it in release builds of projects that use external libraries because it's not binary-compatible with the regular `std::vector` that everyone uses (size is different, for starters). You may know the problem from performance-oriented MSVC builds, where it runs the other way around. It's not useless, but it's limited to debugging. – Wintermute Mar 15 '15 at 17:24
  • By the way, with the changed language it's a good deal less wrong. If you remove the "but will deal more severely with programming errors" bit I will stop arguing. (It is not defined how severely an implementation deals with out-of-bounds accesses through op[], nor indeed that it deals with them at all.) – Wintermute Mar 15 '15 at 17:28
  • @Wintermute: I've now tried to find a wording everyone can agree on. – Christian Hackl Mar 15 '15 at 17:37