Рейтинговые книги
Читем онлайн Освой самостоятельно С++ за 21 день. - Джесс Либерти

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 135 136 137 138 139 140 141 142 143 ... 170

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

Примечание:"Гнилой" код — это шутливый термин, придуманный программистами для объяснения того, как хорошо отлаженные программы вдруг становятся ненадежными и неэффективными. Об этом явлении не стоит забывать, ведь программы часто бывают чрезвычайно сложными, из-за чего многие ошибки, погрешности и ляпсусы могут долгое время оставаться в тени, пока не проявят себя во всей красе. Для защиты от подобной "плесени" нужно писать код таким образом, чтобы самим было несложно поддерживать его работоспособность.

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

Исключения

В C++ исключение — это объект, который передается из области кода, где возникла проблема, в ту часть кода, где эта проблема обрабатывается. Тип исключения определяет, какая область кода будет обрабатывать проблему и как содержимое переданного объекта, если он существует, может использоваться для обратной связи с пользователем. Основная идея использования исключений довольно проста.

• Фактическое распределение ресурсов (например, распределение памяти или захват файла) обычно осуществляется в программе на низком уровне.

• Выход из исключительной ситуации, возникшей при сбое операции из-за нехватки памяти или захвата файла другим приложением обычно реализуется на высоком уровне программирования в коде, описывающем взаимодействие программы с пользователем.

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

Как используются исключения

Создаются блоки try для помещения в них фрагментов кода, которые могут вызвать проблему, например:

try

{

   SomeDangerousFunction();

}

Исключения, возникшие в блоках try, обрабатываются в блоках catch, например:

try

{

   SomeDangerousFunction();

}

catch(OutOfMemory)

{

   // предпринимаем некоторые действия

}

catch(FileNotFound)

{

   // предпринимаем другие действия

}

Ниже приведены основные принципы использовании исключений.

1. Идентифицируйте те области программы, где начинается выполнение операции, которая могла бы вызвать исключительную ситуацию, и поместите их в блоки try.

2. Создайте блоки catch для перехвата исключений, если таковые возникнут, очистки выделенной памяти и информирования пользователя соответствующим образом. В листинге 20.1 иллюстрируется использование блоков try и catch.

Исключения — это объекты, которые используются для передачи информации о проблеме.

Блок try — это заключенный в фигурные скобки блок, содержащий фрагменты программы, способные вызвать исключительные ситуации.

Блок catch — это блок, который следует за блоком try и в котором выполняется обработка исключений.

При возникновении исключительной ситуации управление передается блоку catch, который следует сразу за текущим блоком try.

Примечание:Некоторые очень старые компиляторы не поддерживают обработку исключений. Однако обработка исключений является частью стандарта ANSI C++. Все современные версии компиляторов полностью поддерживают эту возможность. Если у вас устаревший компилятор, вы не сможете скомпилировать и выполнить листинги, приведенные на этом занятии. Однако все же стоит прочитать представленный материал до конца, а затем вернуться к нему после обновления своего компилятора.

Листинг 20.1. Возникновение исключительной ситуации

1: #include <iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: class Array

6: {

7:    public:

8:       // конструкторы

9:       Array(int itsSize = DefaultSize);

10:      Array(const Array &rhs);

11:      ~Array() { delete [] pType;}

12:

13:      // операторы

14:      Array& operator=(const Array&);

15:      int& operator[](int offSet);

16:      const int& operator[](int offSet) const;

17:

18:      // методы доступа

19:      int GetitsSize() const { return itsSize; }

20:

21:      // функция-друг

22:      friend ostream& operator<< (ostream&, const Array&);

23:

24:      class xBoundary { } ; // определяем класс исключений

25:   private:

26:      int *pType;

27:      int itsSize;

28: };

29:

30:

31: Array::Array(intsize):

32: itsSize(size)

33: {

34:    рТуре = new int[size];

35:    for (int i = 0; i<size; i++)

36:    pType[i] = 0;

37: }

38:

39:

40: Array& Array::operator=(const Array &rhs)

41: {

42:    if (this == &rhs)

43:       return *thts;

44:    delete [] pType;

45:    itsSize = rhs.GetitsSiza();

46:    pType = new int[itsSize];

47:    for (int i = 0; i<itsSize; i++)

48:       pType[i] = rhs[i];

49:    return *this;

50: }

51:

52: Array::Array(const Array &rhs)

53: {

54:    itsSize = rhs.GetitsSize();

55:    pType = new int[itsSize];

56:    for (int i = 0; i<itsSize; i++)

57:       pType[i] = rhs[i];

58: }

59:

60:

61: int& Array::operator[](int offSet)

62: {

63:    int size = GetitsSize();

64:    if (offSet >= 0 && offSet < GetitsSize())

65:       return pType[offSet];

66:    throw xBoundary();

67:    return pType[0]; // требование компилятора

68: }

69:

70:

71: const int& Array::operator[](int offSet) const

72: {

73:    int mysize = GetitsSize();

74:    if (offSet >= 0 && offSet < GetitsSize())

75:       return pType[offSet];

76:    throw xBoundary();

77:    return pType[0]; // требование компилятора

78: }

79:

80: ostream& operator<< (ostream& output, const Array& theArray)

81: {

82:    for (int i = 0; i<theArray,GetitsSize(); i++)

83:       output << "[" << i << "] " << theArray[i] << endl;

84:    return output;

85: }

86:

87: int main()

88: {

89:    Array intArray(20);

90:    try

91:    {

92:       for (int ] << 0; j< 100; j++)

93:       {

94:          intArray[j] = j;

95:          cout << "intArray[" << j << "] okay..." << endl;

96:       }

97:    }

98:    catch (Array::xBoundary)

99:    {

100:      cout << "Unable to process your input!n";

101:   }

102:   cout << "Done.n";

103:   return 0;

104: }

Результат:

intArray[0] okay...

intArray[1] okay...

intArray[2] okay...

intArray[3] okay...

intArray[4] okay...

intArray[5] okay...

intArray[6] okay...

intArray[7] okay...

intArray[8] okay...

intArray[9] okay...

intArray[10] okay...

intArray[11] okay...

intArray[12] okay...

intArray[13] okay...

intArray[14] okay...

intArray[15] okay...

intArray[16] okay...

intArray[17] okay...

intArray[18] okay...

intArray[19] okay...

Unable to process your input!

Done.

Анализ: В листинге 20.1 представлен несколько усеченный класс Array, основанный на шаблоне, разработанном на занятии 19.

В строке 24 объявляется новый класс xBoundary внутри объявления внешнего класса Array.

В этом новом классе ни по каким внешним признакам нельзя узнать класс обработки исключительных ситуаций. Он чрезвычайно прост и не содержит никаких данных и методов. Тем не менее это вполне работоспособный класс.

На самом деле было бы неправильно говорить, что он не содержит никаких методов, потому что компилятор автоматически назначает ему стандартный конструктор, деструктор, конструктор-копировщик и оператор присваивания (=), поэтому у него фактически есть четыре метода, но нет данных.

Обратите внимание на то, что его объявление внутри класса Array служит только для объединения двух классов. Как описано в главе 15, класс Array не имеет никакого особого доступа к классу xBoundary, да и класс xBoundary не наделен преимущественным доступом к членам класса Array.

В строках 61—68 и 71—78 операторы индексирования ([]) замещены таким образом, чтобы предварительно анализировать введенный индекс смещения и, если оно окажется вне допустимого диапазона, обратиться к классу xBoundary для создания исключения. Назначение круглых скобок состоит в том, чтобы отделить обращение к конструктору класса xBoundary от использования константы перечисления. Обратите внимание, что некоторые компиляторы компании Microsoft требуют, чтобы определение функции в любом случае заканчивалось строкой с оператором return, согласующейся по типу с прототипом функции (в данном случае возвращение ссылки на целочисленное значение), несмотря на то что в случае возникновения исключительной ситуации в строке 66 выполнение программы никогда не достигнет строки 67. Этот пример говорит о том, что логические ошибки не чужды даже компании Microsoft!

1 ... 135 136 137 138 139 140 141 142 143 ... 170
На этой странице вы можете бесплатно читать книгу Освой самостоятельно С++ за 21 день. - Джесс Либерти бесплатно.

Оставить комментарий