Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt - QList const correctness

A QList<T *> can't easily be const-correct. Consider the function

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

I can change f to

void f(QList<const T *> list)

but then I can't do

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

anymore, since the compiler can't implicitely cast QList<T *> to QList<const T *>. However, I can explicitely reinterpret-cast the QList as follows:

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

This enables me to use the constList template function to cast any QList<T *> into a QList<const T *>, as in

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

and it seems to work fine, but is it actually safe to do this?

like image 639
emkey08 Avatar asked Jun 26 '11 10:06

emkey08


1 Answers

The casting function you're considering, …

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

… may be practical (probably QList does not change its object representation depending on the const-ness of the element type), but it can break const correctness.

First, because casting away the const-ness of the list itself is not const correct: it allows you to change an originally const list.

But even if that formal argument const is removed, like …

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

… there is still a const correctness problem.

The reason is that the list constitutes an additional level of indirection, and with your function is not itself const. Thus, after using your function to get a reference to the list with alleged pointer-to-const elements, you can store in that list a pointer to something that is really const. And then you can use the original list to modify that really const item, bang.

It's the same reason that there is no implicit conversion from T** to T const**.

What you can do without such problems is, with an already const list of pointers to objects, make those pointed to objects const:

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

Formally there's still the reinterpret_cast as a potential problem, but anyone specializating the representation of QList on constness of elements would presumably deserve whatever they got. :-)

Cheers & hth.,

like image 195
Cheers and hth. - Alf Avatar answered Sep 18 '22 05:09

Cheers and hth. - Alf