开发者

Qt - QList const correctness

开发者 https://www.devze.com 2023-03-15 22:58 出处:网络
A QList<T *> can\'t easily be const-correct. Consider the function void f(QList<T *> list)

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 开发者_JAVA百科to work fine, but is it actually safe to do this?


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.,


Const correctness idea is weak and what you found is one of the many reasons. Constness concept only captures a single bit of semantic (change/don't change) and does so badly and at a quite high syntax cost that sometimes even requires code duplication.

One problem of this concept is that it doesn't scale well by composition: for example I could be interested to pass a function a const vector of non-const objects, or a non-const vector of const objects, or a const vector of const objects and getting the syntax right is expensive... just consider how standard c++ was forced to introduce const_iterator because that is of course different from a const iterator.

Over the years I moved from the zealot position of using const correctness in every place I could to the opposite of using it only where I'm forced to. Experience taught me that code that is not obsessed with const correctness becomes cleaner and that const correctness machinery never really catches (at least for me) any logical error but only errors about the const correctness machinery itself. Unfortunately const correctness is one of the things in C++ that you are forced to use because C++ rules say so and there is no way to just avoid using it.

I know I'm going to be downvoted for this post but my suggestion is to keep a critical eye on whatever you read about C++ on this subject; keep the brain on and judge objectively. Just because would be nice for something being true (e.g. that const correctness helps the programmer) unfortunately it doesn't mean it's really true.

No matter how big is the name that signed the book.

Also remember that if a position requires all the rest of the world to be wrong then it's probably a good idea to be at least a little skeptic: most languages, even those born after C++, don't implement this concept.

0

精彩评论

暂无评论...
验证码 换一张
取 消