Qt-QList const корректность


A QList<T *> не может легко быть const-правильным. Рассмотрим функцию

void f(QList<T *> list)
{
    list[0]->constFunction();
}

Я могу изменить f на

void f(QList<const T *> list)

Но тогда я не могу сделать

f(QList<T *>());    //Compile error

Больше, так как компилятор не может имплицитно привести QList<T *> к QList<const T *>. Однако я могу явно переинтерпретировать QList следующим образом:

template <typename T> inline QList<const T *> &constList(const QList<T *> &list)
{
    return (QList<const T *> &)list;
}

Это позволяет мне использовать функцию шаблона constList для приведения любого QList<T *> в QList<const T *>, как в

f(constList(QList<T *>()));

И это, кажется, работает нормально, но на самом деле безопасно ли это делать вот это?

2 6

2 ответа:

Функция приведения, которую вы рассматриваете, ...

template< class T >
inline QList<T const*>& constList( QList<T*> const& list )
{
    return reinterpret_cast< QList<T const*>& >(
        const_cast< QList<T*>& >( list )
        );
}

... может быть практичным (вероятно, QList не изменяет своего объектного представления в зависимости от const-ности типа элемента), но он может нарушать const корректность.

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

Но даже если этот формальный Аргумент const будет удален, как ...

template< class T >
inline QList<T const*>& constList( QList<T*>& list )
{
    return reinterpret_cast< QList<T const*>& >(
        list
        );
}

... есть все еще проблема корректности const.

Причина в том, что список представляет собой дополнительный уровень косвенности, а с вашей функцией не является самим собой const. Таким образом, после использования функции для получения ссылки на список с предполагаемым указателем на элементыconst, Вы можете сохранить в этом списке указатель на то, что на самом деле является const. И тогда вы можете использовать исходный список, чтобыизменить , что действительно const элемент, bang .

Это та же самая причина, по которой существует нет неявного преобразования из T** в T const**.

Что вы можете сделать без таких проблем, так это, имея уже const список указателей на объекты, сделать так, чтобы они указывали на объекты const:
template< class T >
inline QList<T const*> const& constList( QList<T*> const& list )
{
    return reinterpret_cast< QList<T const*> const& >(
        list
        );
}
Формально

Все еще существует reinterpret_cast как потенциальная проблема, но любой, кто специализируется на представлении QList о постоянстве элементов, вероятно, заслуживает того, что они получили. :- )

Ура и ХТ.,

Идея корректности Const слаба, и то, что вы обнаружили, является одной из многих причин. Концепция Constness захватывает только один бит семантики (change / don't change) и делает это настолько плохо и с довольно высокой стоимостью синтаксиса, что иногда даже требует дублирования кода.

Одна из проблем этой концепции заключается в том, что она плохо масштабируется по составу: например, мне было бы интересно передать функции вектор const неконстантных объектов, или вектор const неконстантных объектов, или вектор const const объектов и получение правильного синтаксиса является дорогостоящим... просто рассмотрим, как стандартный c++ был вынужден ввести const_iterator, потому что это, конечно, отличается от const iterator.

За эти годы я перешел от фанатичной позиции использования const корректности во всех возможных местах к противоположной позиции использования ее только там, где я вынужден. Опыт научил меня, что код, который не одержим корректностью const, становится чище, и что механизм корректности const никогда по-настоящему не ловит (по крайней мере, для me) любая логическая ошибка, но только ошибки о самой машине корректности const. К сожалению, корректность const-это одна из вещей в C++, которую вы вынуждены использовать, потому что правила C++ так говорят, и нет никакого способа просто избежать ее использования.

Я знаю, что меня понизят в должности, но мое предложение состоит в том, чтобы критически следить за всем, что Вы читаете о C++ на эту тему; держите мозг включенным и судите объективно. Просто потому, что было бы хорошо, если бы что-то было правдой (например, что const корректность помогает программисту) к сожалению, это не значит, что это действительно так.

Неважно, насколько велико имя, подписавшее книгу.

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