2015-03-15 3 views
-2

Я - абсолютный новичок в программировании. Я получил эту ошибку, создав следующий код.завершение вызова после вызова экземпляра 'std :: out_of_range'

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

ответ

1

массива и векторные индексы в C++ работают от 0 до размера - 1. Таким образом, когда вы говорите

num=planet.size(); 

и позже

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

вы пытаетесь для доступа один за конец Вектор planet. Затем функция-член at выдает исключение типа std::out_of_range, которое никогда не попадает, и из-за этого ваша программа завершается.

Похоже, вы хотели найти векторный указатель, соответствующий названию планеты; вы могли бы сделать это с std::find и std::distance следующим образом:

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

это вернет planet.size() если cPlanet не найден. Однако, вероятно, было бы лучше реализовать все это с помощью std::map.

0

Вот простая программа для воспроизведения поведения:

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

at функция члена генерирует исключение, если вы пытаетесь получить доступ к несуществующему элементу.

Хотя это в основном звучит неплохо, на практике это оказывается практически бесполезным. Использование незаконного векторного индекса почти наверняка является ошибкой программирования, а исключений не должно быть выбрано для ошибок программирования.

Вы можете catchstd::out_of_range исключение для «восстановления» из ошибки или «дескриптор», но серьезно, что вы могли бы сделать на таком низком уровне логики программы?

Для std::vector, предпочитайте оператор []. В вашем случае:

tTime = distance[num]/speed; 

[], как at, но занимает совершенно иную позицию в отношении ошибок программирования; at как «Если вы когда-нибудь позвоните мне с незаконным индексом, я брошу исключение, чтобы мы как-то продолжили, не так ли?», тогда как с оператором [] поведение не определено для незаконных векторных индексов. Это означает, что реализация C++ позволяет просто прекратить работу программы без каких-либо случайных сбоев исключения и «продолжения каким-то образом». Это зависит от того, как вы вызываете компилятор, и обычно требует изучения параметров конфигурации вашего компилятора (например, those for VC++ или those for GCC).

Прекращение действия как можно быстрее - это правильная вещь, когда вы обнаружите, что ваш собственный код неправильный.Не привыкать к поведению at.

+1

На практике любая реализация на C++, как правило, проходит через доступ за пределами границ к вектору с помощью 'operator []' и незаметно делает что-то неправильно с данными, которые он обнаруживает в ссылочной ячейке памяти. Просто не так, что «любая хорошая реализация на С ++» в таких случаях надежно завершается. – Wintermute

+0

@Wintermute: Ну, вы также должны не удалять все эти проверки при компиляции кода. Если только штраф за производительность не отображается. Возможно, лучший способ выразить это: «любая хорошая реализация на C++ позволяет надежно завершать работу». –

+0

@Wintermute Правильно, я никогда не видел такую ​​«хорошую реализацию на C++» за все свои годы, как программист на C++ ;-) Я с радостью предположил, что в 'operator []' не будет накладных расходов. – juanchopanza

Смежные вопросы