32

I have a map that's defined like this

 struct A
 {
  int A;
  int B;
 };
 typedef map<int,A> Amap;

Then I have Amap1 and I want copy it to Amap2

 A a....;
 Amap Amap1,Amap2;
 Amap1[1]=a1;
 Amap1[2]=a2;
 Amap1[3]=a3;
 Amap2.insert(Amap1.begin(), Amap1.end());

Sometimes this work properly, sometimes this copies only the keys and the value 0. Where is my mistake here?

3 Answers 3

78

Copying one map to another can be done with operator = or the copy constructor.

E.g

map<X, Y> mp1; 
//fill mp1 with data
map<X, Y> mp2(mp1); //mp2 is a copy of mp1 (via copy-construction)
map<X, Y> mp3;
mp3 = mp2; // mp3 is also a copy of mp2 (via copy-assignment)
Sign up to request clarification or add additional context in comments.

9 Comments

@Wolf: Both those methods are presented in the answer. This is a collaboratively edited community, if you would like to add to the answer, feel free to edit it.
@Wolf: Please do not substantially modify other people's answers, especially those written FIVE years ago that have already been upvoted by people and accepted by the OP. Feel free to write your own, competing answer.
@LightnessRacesinOrbit I asked for it and the OP explicitly granted it to me: feel free to edit it
@Wolf: That's a contentious issue. It's asked quite a lot on Meta and I don't believe there's any consensus on it. Personally I think that the author should just post a brand new answer if there are substantial changes to be made; it seems dishonest to invalidate all existing votes, no matter how well-intentioned. They were cast to peer-review the original content/suggestion, after all.
Does assignment always copy? What if std::move is being used?
|
18

The code you've posted above will work correctly assuming that Amap2 is empty. If you try to insert a key/value pair into a map that already holds that key, then the old value will be kept and the new one will be discarded. For that reason, if you write

Amap2.insert(Amap1.begin(), Amap1.end());

In some circumstances you might not copy everything over as intended, because duplicate keys won't copy.

To set Amap2 equal to Amap1, consider just using the assignment operator:

Amap2 = Amap1;

This will blindly discard the contents of Amap2, though, so be careful when doing this.

If what you want to do is add all the key/value pairs from Amap2 into Amap1 in a way that completely overrides the existing key/value pairs, you can do so using the following logic. The idea here is similar to the logic behind mergesort - we treat the maps as sequences of sorted values and then continuously blend the two together:

void MergeMaps(map<int, A>& lhs, const map<int, A>& rhs) {
    map<int, A>::iterator lhsItr = lhs.begin();
    map<int, A>::const_iterator rhsItr = rhs.begin();

    while (lhsItr != lhs.end() && rhsItr != rhs.end()) {
        /* If the rhs value is less than the lhs value, then insert it into the 
           lhs map and skip past it. */
        if (rhsItr->first < lhsItr->first) {
            lhs.insert(lhsItr, *rhsItr); // Use lhsItr as a hint.
            ++rhsItr;
        }
        /* Otherwise, if the values are equal, overwrite the lhs value and move both
           iterators forward. */
        else if (rhsItr->first == lhsItr->first) {
            lhsItr->second = rhsItr->second;
            ++lhsItr; ++rhsItr;
        }
        /* Otherwise the rhs value is bigger, so skip past the lhs value. */
        else
            ++lhsItr;

    }

    /* At this point we've exhausted one of the two ranges.  Add what's left of the
       rhs values to the lhs map, since we know there are no duplicates there. */
    lhs.insert(rhsItr, rhs.end());
}

With this, you can write

MergeMaps(Amap1, Amap2);

To copy all the key/value pairs from Amap2 into Amap1.

Hope this helps!

2 Comments

If I wanted to ensure existing keys were overwritten there are 2 options I might choose: I would either use std::copy but instead of std::inserter I would write a custom one that used operator[]. The alternative 2-liner though possibly not quite as efficient is to copy rhsItr then regular-insert lhsItr into the copy and then swap.
@CashCow: The main advantage of my approach compared to the custom inserted is that the brackets run in average case O(lg n) whereas the code I have posted should run in linear time, assuming a good implementation of insert, because of the hinting from having the nearby iterator.
0

The simplest answer now, if you're not opposed to using auto, is this:

Amap Amap1;
Amap1[1] = a1;
Amap1[2] = a2;
Amap1[3] = a3;
auto Amap2 = Amap1;

That's copy construction, as indicated in another answer, but without any need to declare the type of Amap2, since the OP wanted an exact copy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.