Правила программирования на Си и Си++



         

161. Возбуждение исключений из конструктора ненадежно - часть 2


class с

{

    int *pi;

public:

    c() { /*...*/ throw this; }

};

void f( void

)

{

    try

    {

        c  *cp = NULL;

        cp = new c;

        c a_c_object();

    }

    catch( c *points_at_unconstructed_object )

    {

        if( !cp ) // если конструктор, вызванный посредством

                  // new, не выполняется

            delete

points_at_unconstructed_object;

    }

}

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

void f( void

)

{

   c *cp = NULL;  // cp должен быть объявлен снаружи try-блока,

                  // потому что

try-блок образует область

                  // действия, поэтому cp не может быть

                  // доступным в catch-блоке будучи объявлен в

                  // try-блоке.

   try

   {

      c a_c_object;

      cp = new c;

   }

   catch( c *points_at_unconstructed_object )

   {

      if( !cp )   // если конструктор, вызванный посредством

                  // new, не выполняется

         delete

points_at_unconstructed_object;

   }

}

Вы не можете решить эту проблему внутри конструктора, потому что для конструктора нет возможности узнать, получена ли инициализируемая им память от new, или из стека.

Во всех предыдущих примерах деструктор для сбойных объектов вызывается, даже если конструктор не выполнился и возбудил исключение. (Он вызывается или косвенно посредством оператора delete, или неявно при выходе объекта из области действия, даже если он покидает ее из-за возбуждения исключения).

Аналогично, вызов delete

косвенно вызывает деструктор для этого объекта. Я сейчас вернусь к этой ситуации. Перед выходом из этого деструктора незавершенный конструктор должен привести объект в исходное состояние перед тем, как сможет возбудить ошибку. С учетом предшествующего определения класса c

следующий код будет работать при условии, что отсутствует ошибка до оператора new int[128] и new выполнен успешно:




Содержание  Назад  Вперед