可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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.,
回答2:
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.