Я прочитал, что хорошей практикой является проверка деструкторов классов после удаления для элементов данных указателя следующим образом:
if( 0 != m_pPointer)
{
delete m_pPointer;
m_pPointer= 0;
}
Однако я обнаружил, что это не позволяет объявлять константные указатели как элементы данных следующим образом:
Type* const m_pPointer;
Не назначает NULL
указателям (как в моем примере выше) барьером для const-correctness? Каков наилучший способ? Сохраняйте все const
и прекратите назначать NULL
удалённому указателю или объявлять non-const
указатели, даже если их адрес никогда не изменяется?
Это плохая практика по следующим причинам:
delete
он добавляет ненужный код. delete
обрабатывает нулевые указатели, ничего не делая. Хорошая практика заключается в том, чтобы свести к минимуму количество кода.if
идет впустую и является ненужным бременем.
delete m_pPointer; m_pPointer= 0;
в нашем коде? Присвоение NULL указателю гарантирует, что, если что-то позднее будет вызвано для этого указателя, программа потерпит крах. Разве это не хорошо?
"Лучший способ сделать" - это:
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
, без деструктора.
Странная ситуация может быть вызвана, когда вы связываете статический 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
)
Удаление нулевого указателя гарантировано в безопасности, так что нулевая проверка бессмысленна.
Если у класса есть член, который является указателем const для неконстантного объекта, то вы говорите, что значение указателя НЕ изменяется в течение срока жизни объекта-обертки - в этом случае вы должны сделать это только в том случае, если объект, на который указывает, будет жить так долго или дольше, чем обертывающий объект, и объект-обтекатель никогда не захочет указывать на другой объект.
Тот факт, что у вас есть эта проблема, просто означает, что вы использовали указатель const в неправильном месте. Вы утверждаете, что в вашем случае значение указателя никогда не изменяется, но в вашем примере оно явно делает - оно изменяется на null.
delete
затем new
, Если указанный объект создается в списке инициализаторов и уничтожается в деструкторе, нет необходимости устанавливать его в null, и он может быть указателем const - или даже лучше просто поместить его в стек.
0
самом деле помогает с чем-либо? Я видел этот шаблон раньше, но не смогу помочь, если вы не экспортируете ссылки на указатель.