Считается ли 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_casts, но размещает приведенную логику в центральном месте поиска. Редко бывает, что такой virtual вызов является узким местом вашей программы.

Более интересным является то, что вы делаете, если вы не нашли Root? Вернуть nullptr вероятно, что означает обработку этого на всех сайтах вызовов, по крайней мере, на уровне Assertв отладке. Если предполагается, что сайты с вызовами не справляются, верните Root& вместо этого, и имеют сбой вызова прекратить / выйти (после Assert) в отладке (или выпуске, если вы проверите его там, после регистрации / уведомления / и т. д.).

Если вы знаете, что r имеет тип Root, тогда статическое приведение полностью безопасно. Фактически, единственная причина, по которой компилятор позволяет вам использовать static_cast в этом контексте, потому что Root а также Object совместимы. Если вы попробуете это с двумя несовместимыми типами, это приведет к ошибке компилятора - reinterpret_cast нужен в этом случае.

Другие вопросы по тегам