tags:

views:

95

answers:

5

I try to populate the content of a c++ map within a loop scope.

#include <set>
#include <map>

map<int, set<int> > maps;

for (int i=0; i<10; i++) {
   set<int> seti;    // content: a set of integers
   seti.insert(i);
   seti.insert(...);
   maps.insert ( pair<int,set<int> >(i,seti) );
}

The question is: does maps.insert copy the pair content? If the pair instance is invalid after each loop scope, then such code should fail.

How should I properly generate map content (with pointer and new the instance?) and how to clean up a map properly?

thanks for any suggestion for best practices.

--- UPDATE ---

map<int, set<int> >::iterator it;
int k      = (*it).first;     
set<int> v = (*it).second;       

is now the 'v' also a copied one from the real instance stored in map?
if yes, than I have no way to 'directly' update the map content.

+4  A: 

Yes, it copies the content. So a new copy of the set gets inserted at each iteration of the for loop. If that is what you want, you can do it more succinctly using the make_pair function:

#include <set> 
#include <map> 

map<int, set<int> > maps; 

for (int i=0; i<10; i++) { 
   set<int> seti;    // content 
   seti.insert(i); 
   maps.insert ( std::make_pair(i,seti) ); 
} 

It is not clear to me why you want a set with only a single element, unless you plan to add elements to it in the future.

UPDATED: In answer to your update. As long as the value in your map is a container of a basic value type, any updates you make to it will not affect the original value you inserted into the map.

Michael Goldshteyn
yes, later I will retrieve the vectors and update them.
elgcom
please see my updated question. Can I directly access the vector instead of copied instance?
elgcom
+1  A: 

The code you have posted should work just fine. Because of regular type semantics the values will be copied where they belong. The map (and all instances of the regular types the map contains) will destruct properly when they fall out of scope.

fbrereto
+5  A: 

You do not have to explicitly create the set object, as it will be created in the map when you access it with the [] operator. Hence, you can simply write

#include <set>
#include <map>

map<int, set<int> > maps;

for (int i=0; i<10; i++) {
   maps[i].insert(i);
}
bitmask
A: 

Yes, the whole set is copied inside, which is a performance bottleneck. I don't like the solutions proposed because of this. And also, as you ask using pointers, you can do this one safely using boost::shared_ptr. The code could look like this:

#include <set>
#include <map>
#include <boost/shared_ptr.hpp>

// I add typedefs for clarity
typedef boost::shared_ptr< set<int> > set_ptr;

using namespace std;

map<int, set_ptr > maps;

for (int i=0; i<10; i++) {
   set_ptr seti( new set<int>());    // content
   seti->insert(i);
   maps.insert ( std::make_pair(i,seti) );
}

Note that now you're only copying safe pointers, that get deleted when maps gets deleted.

Diego Sevilla
How do you know it's a bottleneck in OP's program? For what it's worth, it's probably not. And `shared_ptr` adds overhead too, potentially making your program even slower than his original example.
Potatoswatter
Unnecessary memory copies are always a burden, IMHO :)
Diego Sevilla
@Potatoswatter: Yes, you're right. In some circumnstances (I insist, not usually), this may lead to a slower program. However, I find it a better practice to avoid memory copies of complex or potentially large structures in favor of (safe) pointer manipulation.
Diego Sevilla
In OP's case, the size of the `set` is known to be one, which means copying it incurs exactly as many heap allocations as creating the `shared_ptr`. It's not apparent that he will ever need to copy it again, and then he is left with the runtime and semantic overhead of `shared_ptr`. If he just copies it once, there is no long-term overhead.
Potatoswatter
A: 

I have to admit that the variable name maps in the following line confused me

map<int, set<int> > maps;

It conveyed a notion that there are many maps, whereas in reality, there is only one.

Two loops are required:

  • one to construct a set of int's, and
  • a second one to insert those sets into the map.

Here is a code sample

typedef std::set< int > IntSet;
typedef std::map< int, IntSet > MapOfIntSet;

MapOfIntSet myMap;     // container

for( int i = 0; i < N; ++i ) {
    IntSet intSet;
    for( int j = i + 1; j < N; ++j ) {
        intSet.insert( j );
    }

    // Both the following line does the same, any one can be used
    // myMap.insert( make_pair( i, intSet ) );
    myMap[ i ] = intSet;
}

A complete program with output is uploaded at codepad.

ArunSaha