Qt - QList const правильность - PullRequest
6 голосов
/ 26 июня 2011

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

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 ]

8 голосов
/ 26 июня 2011

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

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 элемента, взрыва .

По той же причине, что нет неявного преобразованияот 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 в отношении константности элементов, предположительно заслуживает того, что получит.: -)

Приветствия и hth.,

3 голосов
/ 26 июня 2011

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

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

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

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

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

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

...