C ++ NULL указатели и правильность констант

0

Я прочитал, что хорошей практикой является проверка деструкторов классов после удаления для элементов данных указателя следующим образом:

if( 0 != m_pPointer)
{
    delete m_pPointer;
    m_pPointer= 0;
}

Однако я обнаружил, что это не позволяет объявлять константные указатели как элементы данных следующим образом:

Type* const m_pPointer;

Не назначает NULL указателям (как в моем примере выше) барьером для const-correctness? Каков наилучший способ? Сохраняйте все const и прекратите назначать NULL удалённому указателю или объявлять non-const указатели, даже если их адрес никогда не изменяется?

  • 6
    Я бы не согласился, что это хорошая практика. Двойное удаление указателя почти всегда является логической ошибкой в вашем приложении, а установка указателя на нуль после удаления скрывает эту ошибку. Если вы не установите его в null, приложение, вероятно, будет аварийно завершать работу, что является хорошей вещью.
  • 1
    Есть ли у вас сценарий использования, когда установка указателя на 0 самом деле помогает с чем-либо? Я видел этот шаблон раньше, но не смогу помочь, если вы не экспортируете ссылки на указатель.
Показать ещё 28 комментариев
Теги:
pointers
c++11

4 ответа

7
Лучший ответ

Это плохая практика по следующим причинам:

  1. Установка указателя на нуль в деструкторе может маскировать проблему двойного уничтожения. Хорошая практика заключается в том, чтобы выявлять проблемы как можно раньше.
  2. Проверяя указатель на нуль перед delete он добавляет ненужный код. delete обрабатывает нулевые указатели, ничего не делая. Хорошая практика заключается в том, чтобы свести к минимуму количество кода.
  • 0
    Согласовано. Проверка if идет впустую и является ненужным бременем.
  • 0
    Так или нет, чтобы иметь такие конструкции, как delete m_pPointer; m_pPointer= 0; в нашем коде? Присвоение NULL указателю гарантирует, что, если что-то позднее будет вызвано для этого указателя, программа потерпит крах. Разве это не хорошо?
Показать ещё 6 комментариев
1

"Лучший способ сделать" - это:

class foo {
  std::unique_ptr<bar> m_pPointer;
public:
  foo(std::unique_ptr<bar> pPointer)
    : m_pPointer{std::move(pPointer)} {}
};

или для const,

class foo {
  const std::unique_ptr<bar> m_pPointer;
public:
  foo(std::unique_ptr<bar> pPointer)
   : m_pPointer{std::move(pPointer)} {}
};

Нет new, без delete, без деструктора.

1

Странная ситуация может быть вызвана, когда вы связываете статический lib с глобальным или статическим объектом из двух разных общих libs (в Linux), которые позже будут связаны с одним и тем же исполняемым файлом.

Каждый вызов разделяемого объекта lib вызывает конструктор и деструктор, поэтому у вас будет один объект и два вызова конструктора и деструктора для одного и того же объекта (на самом деле у вас будет 2 объекта, сопоставленные с одним и тем же адресом).

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

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

class A{
  obj *x, *y;
  A(){
    x = new obj;
    y = NULL
  }
  ~A(){
    delete x;
    if(y)delete y; // the 'if' here will save the calling and returning run time when NULL. 
  }
  void RecicleX(){
    delete x;
    x = new obj;
  }
  void InitY(){
    assert(y==NULL); //illegal to call init when already
    y = new obj;
  }
  void TermY(){
    assert(y); //illegal to call term when already inited
    delete y;
    y = NULL; //prevent crush in dtor if called after...
  } 
};

x всегда существует, поэтому нет необходимости его проверять, и нет необходимости его обнулять. y может существовать и не может, поэтому я думаю, что вы должны его удалить после удаления. (Возможно, вам также захочется узнать текущее состояние, например, для assert)

1

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

Если у класса есть член, который является указателем const для неконстантного объекта, то вы говорите, что значение указателя НЕ изменяется в течение срока жизни объекта-обертки - в этом случае вы должны сделать это только в том случае, если объект, на который указывает, будет жить так долго или дольше, чем обертывающий объект, и объект-обтекатель никогда не захочет указывать на другой объект.

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

  • 0
    Суть вопроса в том, должно ли значение измениться на ноль. И ответ на этот вопрос - нет, не должен и должен быть постоянным.
  • 0
    Возможно, в вашем реальном мире, который не может быть получен из фрагмента. Тем не менее, когда указатель на член удаляется и переназначается несколько раз за время существования объекта-оболочки, может быть справедливой стратегией всегда гарантировать, что указатель либо указывает на объект, либо на ноль, тогда повторное создание объекта может просто delete затем new , Если указанный объект создается в списке инициализаторов и уничтожается в деструкторе, нет необходимости устанавливать его в null, и он может быть указателем const - или даже лучше просто поместить его в стек.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню