2012-05-22 3 views
2

Мне нужно изучить основы C++ для исследовательского проекта, и я экспериментирую с обработкой ошибок/исключений. Я успешно использовал команду throw, чтобы предвидеть события, которые могут произойти (например, деление на ноль), но я не могу понять, как поймать непредвиденные исключения. Возьмите этот пример кода:C++ обработка непредвиденных ошибок

#include <iostream> 
#include <exception> 
#include <stdexcept> 
using namespace std; 

void arrayOutOfBound() 
{ 
    int a[3] = {1, 2, 3}; 

    try 
    { 
     cout << "This should not display: " << a[5] << endl; 
    } 
    catch(runtime_error &e) 
    /* catch(exception &e)  // also does not work */ 
    { 
     cout << "Error: " << e.what() << endl; 
    } 
} 

int main() 
{ 
    arrayOutOfBound(); 
} 

Я предполагаю, что я должен использовать throw заявления где-то, но предположим, что я действительно не знал, что a[5] не будет работать (или пользователь вошел в этот индекс, и я не проверял для массива размер), то как я могу предотвратить сбой программы? (как это происходит в отладчике Visual C++ Express 2010)

Примечание: если бы я сделал try { int result = a[5]; } сначала, вне блока и попытался использовать cout << result в конце, программа не компилируется. Компилятор пытается мне помочь, но поэтому я не могу попробовать обработку исключений.

+0

Дело не зная того или нет 'а [5]' будет успешным, но (таким же образом) для 'a [x]' для отказа. Если вы не готовы, ваша программа заканчивается, потому что она не обрабатывает ее для вас. Это, конечно, предполагает, что у вас есть класс массива, способный проверять. – chris

ответ

3

Предположим, я действительно не знал, что [5] не будет работать (или пользователь ввел этот индекс, и я не проверял размер массива), то как я могу предотвратить сбой программы?

Вы просто не можете. Доступ за пределы доступа к массиву вызывает неопределенное поведение на C++, он не будет генерировать исключение. Когда вам повезет, вы получите крах.

+0

Ах, ладно. Это звучит обнадеживающе!;-) – Pieter

+0

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

+1

@ Ed S .: Я согласен, это, безусловно, интересно! –

1

Если вы хотите этого поведения, рекомендуем вам написать класс, например. «CheckedArray», который обертывает массив и выполняет проверку границ. Если вы сделаете это в полной общности, это будет класс шаблонов, и вам обязательно нужно будет знать о перегрузке оператора [].

Альтернативно, если вы довольны накладными расходами динамически распределенного массива, используйте std::vector, в частности его функция-член at выдает исключение из индекса вне диапазона. В качестве побочного эффекта ваш массив теперь может быть (повторно) размером во время выполнения.

Еще лучше, если использовать std::array, который также имеет метание at функцию (но не изменяемыми.)

+0

Или используйте что-то вроде 'std :: array', которое уже есть. – chris

+0

@chris: Хорошая точка, обновлено. – ndkrempel

+0

Я понял из книги Дейтеля, что векторы действительно лучше, чем массив, который я использую. Пример был для обработки ошибок. Сначала попробуйте сделать divideByZero(), но компилятору удалось сделать все возможное. К сожалению, в этом случае ;-) – Pieter

1

К сожалению, не могу не процитировать очевидное мем «родные массивы ... это не то, как вы это делаете!» : D

код, который вы написали выше, использует собственный массив, который по сути является местом памяти. поэтому, говоря [5], вы говорите, что я хочу использовать 4 байта по адресу (a + 4 * sizeof (int)) для интерпретации как int. Это не вызовет исключения. это неопределенное поведение и может вернуть мусор. если вы используете -O2 или некоторый такой флаг компилятора, он может возвращать 0 и кстати, это оценка Источник переполнения буфера: D

Вот шаблон класса, который будет решать ваши проблемы:

#include <iostream> 
#include <exception> 
#include <stdexcept> 
#include <vector> 
using namespace std; 

template<class T, size_t COUNT> 
class CheckedArray 
{ 
public: 
    class OutOfBounds : public std::exception 
    { 
     public: 
      virtual const char* what() const throw(){ return "Index is out of bounds"; }  
    }; 
    CheckedArray(){} 
    virtual ~CheckedArray(){} 
    const T& operator[] (size_t index) const 
    { 
     if(index >= COUNT){ throw OutOfBounds(); } 
     return m_array[index]; 
    } 
    T& operator[] (size_t index)  
    { 
     if(index >= COUNT){ throw OutOfBounds(); } 
     return m_array[index]; 
    } 
private: 
    T m_array[COUNT]; 
}; 
void arrayOutOfBound() 
{ 
    //int a[3] = {1, 2, 3}; 

    CheckedArray<int,3> a; 
    a[0] = 1; 
    a[1] = 2; 
    a[2] = 3; 
    try 
    { 
     cout << "This should not display: " << a[5] << endl; 
    } 
    catch(std::exception& e)  // this will kick in 
    { 
     cout << "Error: " << e.what() << endl; 
    } 
} 


int main() 
{ 
    arrayOutOfBound(); 
} 
0

Если вы просто хотите, обработчик ошибок сегментации и такой, вы должны проверить signal.h

// Джон