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

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

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

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

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.

Спасибо.

Ответы [ 4 ]

6 голосов
/ 05 августа 2009

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

В этом случае, если вызов 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;
};
2 голосов
/ 05 августа 2009

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

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

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

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

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

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

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

1 голос
/ 05 августа 2009

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

1 голос
/ 05 августа 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...