Должны ли указатели на «сырые» ресурсы обнуляться в деструкторах? - PullRequest
0 голосов
/ 31 января 2012

Когда я оборачиваю «сырые» ресурсы в класс C ++, в коде деструктора я обычно просто освобождаю выделенные ресурсы, не обращая внимания на дополнительные шаги, такие как обнуление указателей и т. Д. e.g.:

class File
{
public:
  ...

  ~File()
  {
    if (m_file != NULL)
      fclose(m_file);
  }

private:
  FILE * m_file;
};

Интересно, содержит ли этот стиль кода потенциальную ошибку : то есть возможно ли, что деструктор вызывается более одного раза? В этом случае, что нужно сделать в Деструктор будет очищать указатели, чтобы избежать двойного / множественного разрушения:

~File()
{
  if (m_file != NULL)
  {
    fclose(m_file);
    m_file = NULL; // avoid double destruction
  }
}

Аналогичный пример может быть сделан для памяти, выделенной из кучи: если m_ptr - указатель на память, выделенную с помощью new[], в порядке ли следующий код деструктора?

// In destructor:
delete [] m_ptr; 

или указатель тоже должен быть очищен, чтобы избежать двойного уничтожения?

// In destructor:
delete [] m_ptr;
m_ptr = NULL; // avoid double destruction

Ответы [ 3 ]

5 голосов
/ 31 января 2012

Нет. Это полезно, если у вас есть функция Close() или подобное:

void Close()
{
    if (m_file != NULL)
    {
        fclose(m_file);
        m_file = NULL;
    }
}
~File()
{
    Close();
}

Таким образом, функция Close() является идемпотентной (вы можете вызывать ее столько раз, сколько захотите), и вы избегаете одного дополнительного теста в деструкторе.

Но поскольку деструкторы в C ++ могут вызываться только один раз, присваивать указатели NULL там бессмысленно.

Если, конечно, для целей отладки, особенно если вы подозреваете двойное удаление.

2 голосов
/ 31 января 2012

В приложении с ошибками (например, неправильное использование std :: unique_ptr <> может привести к двум std :: unique_ptr <>, содержащим один и тот же необработанный указатель), вы можете получить двойное удаление, как второе выходит за рамки.

Мы заботимся об этих плохих случаях - иначе какой смысл обсуждать установку указателя на nullptr в деструкторе? Все равно уходит!

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

Так что, в целом, я не нахожу установку указателей на nullptr особенно полезной для управления памятью.

Вы можете сделать это, но более надежной альтернативой является выполнение модульных тестов и разумное использование средства проверки памяти , например valgrind .

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

2 голосов
/ 31 января 2012

Если деструктор вызывается более одного раза, у вас уже есть неопределенное поведение.Это также не повлияет на клиентов, которые могут иметь указатель на ресурс самостоятельно, поэтому это не предотвращает двойное удаление.A unique_ptr или scoped_ptr кажутся мне лучшим решением.

...