Вопрос:

C ++: обрабатывать ресурсы, если конструкторы могут генерировать исключения (ссылка на FAQ 17.4]

c++ exception

7424 просмотра

4 ответа

456 Репутация автора

Спасибо за все ответы.

Я переформатировал свой вопрос, чтобы понять состояние указателя на член после того, как конструктор связывающегося класса выдает исключение

Опять мой пример класса :)

class Foo
{
public:
    Foo()
    {
       int error = 0;
        p = new Fred;

        throw error;  // Force throw , trying to understand what will happen to p
    }

   ~Foo()
    {
       if (p)
       {
           delete p;
           p = 0;
       }
     }
private:
   Fred* p;
};

int main()
{
      try
      {
         Foo* lptr = new Foo;
      }
      catch (...)
      {}
}

Consturctor для класса foo выдает исключение по какой-то случайной причине. Я понимаю, что деструктор foo никогда не будет вызван, но в этом случае деструктор для p будет вызван?

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

Благодарю.

Автор: mithuna Источник Размещён: 04.08.2009 11:24

Ответы (4)


2 плюса

267065 Репутация автора

Нет, если это никогда не было выделено.

Но вместо того, NULLчтобы возвращаться при неправильном распределении через new, вы получите исключение std :: bad_alloc.

NULL возвращается malloc C, если распределение не может быть сделано.

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

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

Вообще, бросать исключения в конструкторы лучше всего.

Смотрите мой ответ здесь для расширенного обсуждения .

Автор: Brian R. Bondy Размещён: 04.08.2009 11:28

1 плюс

6874 Репутация автора

Деструктор для pне будет вызван, если выделение памяти для pне удастся.

Автор: Rob Knight Размещён: 04.08.2009 11:29

1 плюс

61832 Репутация автора

Вопрос действительно не имеет никакого смысла. new Fred();никогда не вернет NULL. Он только когда-либо либо успешно создаст объект Fred, либо выдаст исключение. Если бы он вызвал исключение, объект Fred никогда бы не существовал, поэтому его деструктор не был бы вызван.

Автор: Tyler McHenry Размещён: 04.08.2009 11:30

6 плюса

314852 Репутация автора

Решение

Здесь есть похожий вопрос, который охватывает то, что вы спрашиваете.

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

Деструктор класса не будет вызван, потому что объект никогда не был полностью построен. Есть два способа это исправить.

1)

Имейте полностью управляемые исключения в конструкторе:

class Foo
{
public:
    Foo()
    try
    {
        p = new p;

        throw /* something */; 
    }
    catch (...)
    {
       delete p;

       throw; //rethrow. no memory leak
    }
private:
    int *p;
};

2)

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

class Foo
{
public:
    Foo() :
    p(new int)
    {
        throw /* something */; 
    }
private:
    std::auto_ptr<int> p;
};
Автор: GManNickG Размещён: 05.08.2009 12:14
Вопросы из категории :
32x32