Chris
Chris

Reputation: 1244

Replace existing and add new entries in std::map

Consider following snippet:

MapT map;

map["A"] = 1;
map["B"] = 2;
map["C"] = 3;
map["D"] = 4;
map["E"] = 5;

MapT mapSecond;

mapSecond["A"] = 10;
mapSecond["B"] = 20;
mapSecond["C"] = 30;
mapSecond["X"] = 4;
mapSecond["Y"] = 5;

MapT::const_iterator itSecond = mapSecond.begin();
MapT::iterator it = map.begin();

for (; itSecond != mapSecond.end(); ++itSecond)
{
    std::pair<MapT::iterator, bool> pair = map.insert(std::make_pair(itSecond->first, itSecond->second));
    if (!pair.second)
    {
        pair.first->second = itSecond->second;
    }
}

for (; it != map.end(); ++it)
{
    std::cout << it->first << " " << it->second << std::endl;
}

I assume using the returned iterator from insert is the most efficient version.

However at first, I did just thought assigning the iterators only works fine (note I am not dereferencing the iterator anymore here).

1.)

// assigning the dereferenced iterator (i.e.: the underlying std::pair)
// resulting in no match for binary '=' operator for const std::string
*pair->first = *itsecond;

I know its obsolete as I already matched the key and only care about the value. This error occurs only because of the key being a const std::string If I am not completely out of my mind :D

2.)

// assigning the iterator itself
// does not compile as long as itSecond is of type const_iterator ?
// does nothing in case itSecond is of type iterator
pair.first = itSecond;

This is the thing I actually don't understand. How is the assignment of an iterator in a std::map supposed to behave? Although I do program C++ for a few years already, I never encountered a scenario where I did so for any container. I have not found a lot of information about assigning iterators in general during a bit of research.

And finally would there be an even more elegant way of doing what I want to achieve (using C++11 features, maybe C++14)?

Upvotes: 0

Views: 13222

Answers (3)

Some programmer dude
Some programmer dude

Reputation: 409166

Why make it so complicated? Why not simply

map[itSecond->first] = itSecond->second;

If they key exists, the data will be changed. If the key doesn't exist, then the pair will be inserted.


Also don't forget that the value_type of std::map (and std::unordered_map for that matter) is std::pair<const Key, T>.

As the key is constant you can't simply assign or copy iterators, you can only assign or copy the value.

Upvotes: 9

user202729
user202729

Reputation: 3955

To answer the first question

How is the assignment of an iterator in a std::map supposed to behave?

:

MapT::Iterator satisfies BidirectionalIterator, which satisfies ForwardIterator, which satisfies Iterator.

An Iterator is CopyAssignable.

So the assignment t = v; will make

  • The value of t is equivalent to the value of v.
  • The value of v is unchanged.

In this case substitute t with pair.first, and v with itSecond. Note that the map is not changed with this.

(imagine pointers. Of course assigning pointers won't modify contents they point to)

Upvotes: 1

Qubit
Qubit

Reputation: 1255

Assuming C++17 is okay, you can use merge: https://en.cppreference.com/w/cpp/container/map/merge

But it doesn't overwrite the data, so you'd have to merge the first into the second.

Upvotes: 0

Related Questions