Считается ли static_cast из базы в производный "безопасным" в ЭТОМ конкретном контексте?
В дереве объектов полиморфной иерархии только Root
Тип экземпляра имеет null
_parent
, Я использую этот метод для извлечения корневого объекта определенного узла дерева:
inline Root * root() {
Object * r = this;
while (r->_parent) r = r->_parent;
return static_cast<Root *>(r);
}
Я читал, что статическое приведение от базового к производному обычно не считается безопасным, но как насчет моего конкретного сценария, где Root
тип может быть идентифицирован null
_parent
?
2 ответа
Это безопасно, пока ваш инвариант держится. Однако инварианты, применяемые к большим частям больших баз кода, редко остаются в силе.
По крайней мере, я бы вставил Assert(dynamic_cast<...>(...))
здесь и в любом месте parent
модифицируется, чтобы попытаться применить инвариант при отладке.
Другим подходом было бы разоблачить virtual Root* as_root()
который возвращает толькоnullptr
в Root
, Это дороже, чем (большинство) static_cast
s, но размещает приведенную логику в центральном месте поиска. Редко бывает, что такой virtual
вызов является узким местом вашей программы.
Более интересным является то, что вы делаете, если вы не нашли Root
? Вернуть nullptr
вероятно, что означает обработку этого на всех сайтах вызовов, по крайней мере, на уровне Assert
в отладке. Если предполагается, что сайты с вызовами не справляются, верните Root&
вместо этого, и имеют сбой вызова прекратить / выйти (после Assert
) в отладке (или выпуске, если вы проверите его там, после регистрации / уведомления / и т. д.).
Если вы знаете, что r
имеет тип Root
, тогда статическое приведение полностью безопасно. Фактически, единственная причина, по которой компилятор позволяет вам использовать static_cast
в этом контексте, потому что Root
а также Object
совместимы. Если вы попробуете это с двумя несовместимыми типами, это приведет к ошибке компилятора - reinterpret_cast
нужен в этом случае.