Qt-interest Archive, April 2008
QMap::operator[]
Message 1 in thread
Hi,
In Qt 3.3.8 the const operator QMap::operator[] returned a constant
reference:
const T & QMap::operator[] ( const Key & k ) const
In 4.3.4 the same operator now returns a constant object:
const T QMap::operator[] ( const Key & key ) const
Why was changed that important operator?
Temporary object that created with this operator results in hidden errors!
Thanks,
Vladimir
--
[ signature omitted ]
Message 2 in thread
Vladimir Romanovskiy wrote:
> In Qt 3.3.8 the const operator QMap::operator[] returned a constant
> reference:
>
> const T & QMap::operator[] ( const Key & k ) const
>
> In 4.3.4 the same operator now returns a constant object:
>
> const T QMap::operator[] ( const Key & key ) const
>
> Why was changed that important operator?
> Temporary object that created with this operator results in
> hidden errors!
I can only guess, but probably efficiency reasons.
If whatever you store in a container class generates "hidden errors"
when it is copied, you shouldn't put it in a container class at all.
Instead you should store pointers in the container (or QPointers or even
QSharedDataPointers).
Cheers,
Peter
--
[ signature omitted ]
Message 3 in thread
Peter Prade wrote:
> Vladimir Romanovskiy wrote:
>
>> In Qt 3.3.8 the const operator QMap::operator[] returned a constant
>> reference:
>>
>> const T & QMap::operator[] ( const Key & k ) const
>>
>> In 4.3.4 the same operator now returns a constant object:
>>
>> const T QMap::operator[] ( const Key & key ) const
>>
>> Why was changed that important operator?
>> Temporary object that created with this operator results in
>> hidden errors!
>>
>
> I can only guess, but probably efficiency reasons.
>
How the creation of temporary object could be ever faster then a
reference to object ?!
> If whatever you store in a container class generates "hidden errors"
> when it is copied, you shouldn't put it in a container class at all.
>
You do not understand. The "hidden errors" are create not by the
"whatever", but rather temporary object itself.
Here is an example to show the problem.
const QString * get( const QMap<QString,QStrng> aMap , QString key)
{
return & aMap[key];
}
In Qt 3.3.8 the function returns a constant pointer to an object inside
the map.
In Qt 4.3.4 the functions returns a constant pointer to a temporary object.
I hope you understand the difference.
> Instead you should store pointers in the container (or QPointers or even
> QSharedDataPointers).
>
There is no reason to get rid of good old value container.
> Cheers,
> Peter
>
Thanks,
Vladimir
Message 4 in thread
> You do not understand. The "hidden errors" are create not by
> the "whatever", but rather temporary object itself.
>
> Here is an example to show the problem.
> const QString * get( const QMap<QString,QStrng> aMap , QString key)
> {
> return & aMap[key];
> }
I'm sorry, but your example doesn't make any sense. Why not return
QString here?
> In Qt 3.3.8 the function returns a constant pointer to an
> object inside the map.
> In Qt 4.3.4 the functions returns a constant pointer to a
> temporary object.
>
> I hope you understand the difference.
Of course, that's why you shouldn't return a pointer - there is no
reason for this (since QString is implicitly shared)
> Instead you should store pointers in the container (or
> QPointers or even
> QSharedDataPointers).
>
>
> There is no reason to get rid of good old value container.
I'm not saying you should get rid of value containers. I'm saying you
should only put values (that can be copied without errors emerging) into
containers. Some operations on containers might make copies and discard
your "original values". (And with them all pointers pointing there!)
If you absolutely need to point at the objects in the map, consider
storing pointers in the map instead.
Cheers,
Peter
--
[ signature omitted ]
Message 5 in thread
Peter Prade wrote:
>> You do not understand. The "hidden errors" are create not by
>> the "whatever", but rather temporary object itself.
>>
>> Here is an example to show the problem.
>> const QString * get( const QMap<QString,QStrng> aMap , QString key)
>> {
>> return & aMap[key];
>> }
>>
>
> I'm sorry, but your example doesn't make any sense. Why not return
> QString here?
>
>
>> In Qt 3.3.8 the function returns a constant pointer to an
>> object inside the map.
>> In Qt 4.3.4 the functions returns a constant pointer to a
>> temporary object.
>>
>> I hope you understand the difference.
>>
>
> Of course, that's why you shouldn't return a pointer - there is no
> reason for this (since QString is implicitly shared)
>
>
QString is not a matter in the sample. If it helps please consider the
sample in the form:
struct CFoo { std::string m_strBar; };
const CFoo * get( const QMap<QString, CFoo> & aMap , QString key)
{
return & aMap[key];
}
>> Instead you should store pointers in the container (or
>> QPointers or even
>> QSharedDataPointers).
>>
>>
>> There is no reason to get rid of good old value container.
>>
>
> I'm not saying you should get rid of value containers. I'm saying you
> should only put values (that can be copied without errors emerging) into
> containers. Some operations on containers might make copies and discard
> your "original values". (And with them all pointers pointing there!)
>
> If you absolutely need to point at the objects in the map, consider
> storing pointers in the map instead.
>
> Cheers,
> Peter
>
>
I am afraid, but instead of following STL rules, Qt wants to invent own
container rules
( like Microsoft did with MFC, where are now those containers ).
I see only reason of such changes in merging STL interface with implicit
shearing.
Regards,
Vladimir
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
Message 6 in thread
2008/4/21, Vladimir Romanovskiy <3504-214@xxxxxxxxx>:
> I am afraid, but instead of following STL rules, Qt wants to invent own
> container rules
Note that STL doesn't even provide a non-const operator[] in its map
classes :-) Precisely because of the issue with non-existing elements.
--
[ signature omitted ]
Message 7 in thread
Julien Cugnière wrote:
> 2008/4/21, Vladimir Romanovskiy <3504-214@xxxxxxxxx>:
>
>> I am afraid, but instead of following STL rules, Qt wants to invent own
>> container rules
>>
>
> Note that STL doesn't even provide a non-const operator[] in its map
> classes :-) Precisely because of the issue with non-existing elements.
>
>
It would be nice to have a definition ( aka QT_NO_STL or
QT_NO_CAST_FROM_ASCII)
that would strict container interfaces to STL rules.
Message 8 in thread
Actually.. It doesn't provide a "const operator[]" in its map...
STL is very clear, if you call operator[] on a key that does not exist in the map, it will create a node at that key, and insert the default value at that node.
So in STL, if you want the value at the map, and you don't want to grow the map, you do a find first, and check to see if the iterator is valid.
For QT, they basically wrap that check for you...
Just like STL, for a non-const map, the map will grow if the key is not in the map... and the value set is the default constructor for the value type.
However, unlike STL, TT provides a const version. If it does not exist, they return the default constructor for the value type. If it does exist it returns the value.
If you want to use it with a better default value. Use value( key, defaultValue ), rather operator[]
As to 3.3.8 it was easy enough to look at the code....
The const operator[ key ] returned the results of find( key ).data() (since find returned a ConstIterator) If key cant be found, an iterator pointing to last node is constructed, which called the default constructor for both the key and value.
The net result, is you had a reference to a temporary object... which is problematic at best.
As to the "strict container interfaces for STL" well... QT is not STL... they have put quite a bit of effort to ease the transition, by having STL like iterators...
That said, the #QT_STRICT_STL_CONTAINER_INTERFACE definition, would disable your operator[] for a const map, and thisconversation would be moot
Scott
From: Vladimir Romanovskiy [mailto:3504-214@xxxxxxxxx]
Sent: Monday, April 21, 2008 6:39 AM
To: Julien Cugnière
Cc: qt-interest@xxxxxxxxxxxxx
Subject: Re: AW: AW: QMap::operator[]
Julien Cugnière wrote:
2008/4/21, Vladimir Romanovskiy <3504-214@xxxxxxxxx> <mailto:3504-214@xxxxxxxxx> :
I am afraid, but instead of following STL rules, Qt wants to invent own
container rules
Note that STL doesn't even provide a non-const operator[] in its map
classes :-) Precisely because of the issue with non-existing elements.
It would be nice to have a definition ( aka QT_NO_STL or QT_NO_CAST_FROM_ASCII)
that would strict container interfaces to STL rules.
Message 9 in thread
2008/4/21, Vladimir Romanovskiy <3504-214@xxxxxxxxx>:
> Here is an example to show the problem.
> const QString * get( const QMap<QString,QStrng> aMap , QString key)
> {
> return & aMap[key];
> }
>
> In Qt 3.3.8 the function returns a constant pointer to an object inside the
> map.
> In Qt 4.3.4 the functions returns a constant pointer to a temporary object.
What happens if "key" is not in the map ? The operator[] can't insert
a new value into the map, because it's const. So it has to return a
temporary value. I don't know what Qt 3.3.8 did in this case, but it
can't have been sane. That's probably why they changed it !
In your particular case, you'll have to either use a map of pointers,
or make your map non-const. The non-const operator[] returns
references to objects inside the map, because it can insert a default
value if necessary.
--
[ signature omitted ]
Message 10 in thread
On Monday 21 April 2008 14:48:48 Vladimir Romanovskiy wrote:
> Here is an example to show the problem.
> const QString * get( const QMap<QString,QStrng> aMap , QString key)
> {
> return & aMap[key];
> }
Just use -Wall. When you do, you'll get something like
test.cpp: In function âconst QString* get(QMap<QString, QString>, QString)â:
test.cpp:6: warning: taking address of temporary
Others have pointed out that there is no trivially right way to implement
operator[](key_t) const
--
[ signature omitted ]