Например
struct A
{
void foo() {};
};
struct B
{
B() {}
void setA(A* a) { mA = a; }
foo() { mA->foo(); }
A *mA;
};
Есть A
связанный (просто адрес) внутри B
, А также B::mA
не должен быть null
, Я обычно забываю setA
и ошибки введены. Какая хорошая практика, чтобы избежать этого? А как насчет setA
как следующий?
void B::setA(A& a) { mA = &a; }
Первое, и самое главное, никогда не оставлять указатель
неинициализированный. Как минимум, установите его на nullptr
(или же NULL
в
pre-C ++ 11) в конструкторе, так что вы можете хотя бы проверить его на валидность
потом.
Помимо этого, многое зависит от того, на что оно должно указывать:
Если срок службы того, на что он указывает, гарантированно простирается за пределы
время жизни вашего объекта (в обоих направлениях: он существует до вашего
объект создан, и будет продолжать существовать после того, как ваш объект
), передайте его как ссылку на конструктор и возьмите
адрес ссылки для инициализации указателя.
Если срок действия того, на что он указывает, может начаться только после
объект построен, то вы должны установить указатель на нуль в
конструктор, назначьте ему в setA
и убедитесь, что это
не нуль каждый раз, когда вы хотите его использовать.
Если время жизни того, на что он указывает, может закончиться до того, как ваш объект
разрушен, тогда вам нужен какой-то вариант шаблона наблюдателя,
уведомить ваш объект о том, что указанный объект был разрушен,
и установите указатель на ноль. В этом случае вам также придется проверить
для нуля каждый раз перед использованием. В прошлом я использовал ManagedPtr
для этого, но это не универсальное решение. (Указатель будет нулевым,
но если указатель находится на карте или что-то, что обычно
случай, он не удалит запись с карты.)
Если время жизни вашего объекта должно влиять на время жизни
указал на объект, то вы должны посмотреть на использование std::shared_ptr
,
Я обнаружил, что такие случаи очень редки в реальном коде, но они случаются.
(Обратите внимание, что если вы используете std::shared_ptr
, ты должен быть очень, очень
осторожный. Вы можете построить только один std::shared_ptr
из любого данного
необработанный указатель без проблем. В нашей собственной кодовой базе мы
запрещенный std::shared_ptr
и использовать нашу собственную инвазивную ссылку
указатель, чтобы избежать таких проблем. std::shared_ptr
был
тщательно разработан, чтобы максимизировать риск висящих указателей и
несколько удалений одного и того же объекта.)
Лучший способ — избегать указателей. Если вам нужно использовать указатели, рассмотрите возможность использования умных указателей, таких как std::unique_ptr
или же std::shared_ptr
. И всегда, всегда инициализируйте указатели, либо равные нулю (если вы не используете умные указатели), либо тому, что вы выделили. И всегда всегда всегда проверьте на ноль, прежде чем использовать их.
Используйте ссылку в качестве первого выбора, если объект всегда инициализируется раньше B
объект:
struct B
{
B(A& a) : mA(a) {}
foo() { mA.foo(); }
A& mA;
};
A a;
B b(a);
«Я обычно забываю setA, и появляются ошибки».
Поэтому заставьте себя установить его конструкторами:
struct B
{
public:
B(A *a) : ma(a) {}
private:
A *mA;
};
И разреши foo
Проверь это:
foo()
{
if (mA)
mA->foo();
else
// handle it, throw exception, ignore, ...!
}