Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"stl - C++: How can I stop map's operator[] from inserting bogus values? - Stack Overflow"

49 views
Skip to first unread message

Lynn McGuire

unread,
Jul 14, 2016, 8:51:54 PM7/14/16
to
"stl - C++: How can I stop map's operator[] from inserting bogus values? - Stack Overflow"
http://stackoverflow.com/questions/10684888/c-how-can-i-stop-maps-operator-from-inserting-bogus-values

Looks like the fix is to use find () instead of [].

Am I missing anything here ?

Thanks,
Lynn

Lynn McGuire

unread,
Jul 14, 2016, 10:04:26 PM7/14/16
to
And I found my bug ! And lo, the bug was causing new members of the std::map to be created, totally confusing the issue.

for (std::map <int, int>::const_iterator i = itemIndexes.begin (); i != itemIndexes.end (); i++)
{
// the index is the key of the pair
int itemIndex = i -> second;
DataItem * item = ownerGroup -> getItem (itemIndexes [itemIndex], itemRelationships [itemIndex]);
if (item)
item = item -> inputOff (ownerGroup);
}

The bug was:

int itemIndex = i -> second;

needs to be:

int itemIndex = i -> first;

Thanks,
Lynn

Alf P. Steinbach

unread,
Jul 14, 2016, 10:39:02 PM7/14/16
to
On 15.07.2016 04:04, Lynn McGuire wrote:
> On 7/14/2016 7:51 PM, Lynn McGuire wrote:
>> "stl - C++: How can I stop map's operator[] from inserting bogus
>> values? - Stack Overflow"
>>
>> http://stackoverflow.com/questions/10684888/c-how-can-i-stop-maps-operator-from-inserting-bogus-values
>>
>>
>> Looks like the fix is to use find () instead of [].
>>
>> Am I missing anything here ?

Dunno, but `at` is a nice function, and `const` prevents modification.

You can't use `[]` with a `const` map, but you can use `at`.


> And I found my bug ! And lo, the bug was causing new members of the
> std::map to be created, totally confusing the issue.
>
> for (std::map <int, int>::const_iterator i = itemIndexes.begin (); i
> != itemIndexes.end (); i++)
> {
> // the index is the key of the pair
> int itemIndex = i -> second;
> DataItem * item = ownerGroup -> getItem (itemIndexes
> [itemIndex], itemRelationships [itemIndex]);
> if (item)
> item = item -> inputOff (ownerGroup);
> }
>

Note, one `index` but two `indices`. I believe. ;-)

Also note that there's no point in updating `item`, except to support
debugging, since its scope ends just after.

I think I'd express that loop like this:

for( auto const& pair : item_indices )
{
int const i = pair.first;
if( Data_item* const p_item = owner_group->item( pair.second,
item_relationships.at( i ) ) )
{
item->input_off( owner_group );
}


> The bug was:
>
> int itemIndex = i -> second;
>
> needs to be:
>
> int itemIndex = i -> first;
>


Cheers!,

- Alf

Lynn McGuire

unread,
Jul 15, 2016, 2:06:26 AM7/15/16
to
The variable item can have multiple owners. If so, it will get copy on
written and get a new address. I set item to that new address just in
case I want to debug it.

Lynn


Öö Tiib

unread,
Jul 15, 2016, 6:40:33 PM7/15/16
to
The 'std::map' template is IMHO actually *overburdened* with
element-searching operations. There are 'std::map::operator[]',
'std::map::find', 'std::map::lower_bound' and 'std::map::at'.

So real question is perhaps when to use one or other from these 4.
My impression is that best is to use 'at' when lack of searched
element is exceptional (or "impossible").
If lack of searched element is normal then we should choose one of
other three depending on what we do when element wasn't found.
When we never insert the missing element then best is 'find'.
When we always insert the missing element then best is 'operator[]'.

When something about other 3 operations did not suit us (for example
that we only sometimes insert that missing element) then 'lower_bound'
(and 'emplace_hint') is likely the tool.

Alain Ketterlin

unread,
Jul 16, 2016, 7:40:09 AM7/16/16
to
Öö Tiib <oot...@hot.ee> writes:

> On Friday, 15 July 2016 03:51:54 UTC+3, Lynn McGuire wrote:
>> "stl - C++: How can I stop map's operator[] from inserting bogus
>> values? - Stack Overflow"
>> http://stackoverflow.com/questions/10684888/c-how-can-i-stop-maps-operator-from-inserting-bogus-values
>>
>> Looks like the fix is to use find () instead of [].
>>
>> Am I missing anything here ?
>
> The 'std::map' template is IMHO actually *overburdened* with
> element-searching operations. There are 'std::map::operator[]',
> 'std::map::find', 'std::map::lower_bound' and 'std::map::at'.

operator[] is here to save one search through the map for logic like:
"if it's there, update it, otherwise insert it", because insert() will
not overwite an existing entry. I agree the choice of operator[] for
this semantic is unfortunate (and it works only with default
constructible types). I guess syntax like "m[k] = v;" to populate a map
was irresistible, as was the whole operator overloading craze at that
time.

lower_bound is a different beast: it uses the strict ordering of keys to
locate a position, but you can't use it to know whether the key is
present without an additional comparison.

> So real question is perhaps when to use one or other from these 4.
> My impression is that best is to use 'at' when lack of searched
> element is exceptional (or "impossible").
> If lack of searched element is normal then we should choose one of
> other three depending on what we do when element wasn't found.
> When we never insert the missing element then best is 'find'.
> When we always insert the missing element then best is 'operator[]'.
>
> When something about other 3 operations did not suit us (for example
> that we only sometimes insert that missing element) then 'lower_bound'
> (and 'emplace_hint') is likely the tool.

Yes, different use cases. Probably not minimal in terms of operations
(compare with Java Map, for instance), but coherent as a whole.

-- Alain.

Öö Tiib

unread,
Jul 16, 2016, 12:27:55 PM7/16/16
to
On Saturday, 16 July 2016 14:40:09 UTC+3, Alain Ketterlin wrote:
> Öö Tiib <oot...@hot.ee> writes:
>
> > On Friday, 15 July 2016 03:51:54 UTC+3, Lynn McGuire wrote:
> >> "stl - C++: How can I stop map's operator[] from inserting bogus
> >> values? - Stack Overflow"
> >> http://stackoverflow.com/questions/10684888/c-how-can-i-stop-maps-operator-from-inserting-bogus-values
> >>
> >> Looks like the fix is to use find () instead of [].
> >>
> >> Am I missing anything here ?
> >
> > The 'std::map' template is IMHO actually *overburdened* with
> > element-searching operations. There are 'std::map::operator[]',
> > 'std::map::find', 'std::map::lower_bound' and 'std::map::at'.
>
> operator[] is here to save one search through the map for logic like:
> "if it's there, update it, otherwise insert it", because insert() will
> not overwite an existing entry. I agree the choice of operator[] for
> this semantic is unfortunate (and it works only with default
> constructible types). I guess syntax like "m[k] = v;" to populate a map
> was irresistible, as was the whole operator overloading craze at that
> time.

Your analysis seems correct. Operator overloading was fancy feature
and all container example codes do start by filling containers with
bogus values (that is unusual use-case in actual code).
Also the novices deserve some of "Gotcha!" and "RTFM!" anyway.
Sad that C++ has somewhat too lot of that on each step.

>
> lower_bound is a different beast: it uses the strict ordering of keys to
> locate a position, but you can't use it to know whether the key is
> present without an additional comparison.

I imagine that 'lower_bound' is not different beast but component.
Other three operations feel like convenience wrappers around 'lower_bound'
that do that last additional compare internally:

// what 'm[k]' does
auto it = m.lower_bound(k);
if (it == m.end() || m.key_comp()(k, it->first)) // <- the last compare
{
// 'at' throws here; 'find' assigns 'm.end()' to 'it'
it = m.emplace_hint(it, k, Value());
}
// now 'it->second' is same as 'm[k]'

>
> > So real question is perhaps when to use one or other from these 4.
> > My impression is that best is to use 'at' when lack of searched
> > element is exceptional (or "impossible").
> > If lack of searched element is normal then we should choose one of
> > other three depending on what we do when element wasn't found.
> > When we never insert the missing element then best is 'find'.
> > When we always insert the missing element then best is 'operator[]'.
> >
> > When something about other 3 operations did not suit us (for example
> > that we only sometimes insert that missing element) then 'lower_bound'
> > (and 'emplace_hint') is likely the tool.
>
> Yes, different use cases. Probably not minimal in terms of operations
> (compare with Java Map, for instance), but coherent as a whole.

Some things are clearly impossible to do with Java Map without
needlessly searching it twice. The use case of map::operator[] is most
unusual for me but the problem domains likely differ.
0 new messages