2

I have an std:map defined as follows:

std:map<std::string country, std::vector<SomeClass> events>; 

Holds some events that will happen in some countries in the world.

I want my main function to create this map given a name to the key but without inserting a value. Let's say that the key is the name of a country. I want to create the "position" "USA" without inserting an event that will happen in the future.

My event() function will enter a new even without checking if the key is valid

Is this possible? Somehow to enter a value_pair with "empty" value?

UPDATE: No boost ...

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
cateof
  • 6,608
  • 25
  • 79
  • 153
  • 1
    Just to clarify, do you mean without inserting a value (which would initially be an empty vector) or without inserting an event (where an event is an element in the vector)? – hmjd Nov 17 '11 at 10:17
  • @hmjd, without inserting an event would be just fine. – cateof Nov 17 '11 at 10:23
  • The STL does not use the `std` namespace. Only the C++ Standard Library is permitted to do that. – Lightness Races in Orbit Nov 17 '11 at 10:24
  • @cateof then Xion's answer below would suffice. – hmjd Nov 17 '11 at 10:25
  • @TomalakGeret'kal I removed my comment – cateof Nov 17 '11 at 10:32
  • 1
    @TomalakGeret'kal: A bit too picky on the STL vs. `std::` namespace... considering that what was once called STL is part of the standard library and is still commonly called by that name, just as ADL is many times called Koening Lookup... Also, unless you are willing to edit the almost 3500 questions tagged [stl] in favor of [stdlib] (used a few hundred times) you are better off leaving the tag as `STL` – David Rodríguez - dribeas Nov 17 '11 at 11:21
  • @DavidRodríguez-dribeas: Not "picky" at all. It is a fact that the STL is _not allowed_ to place symbols in namespace `std`. The sooner people actually learn this essential truth the better; too much ignorance on the subject at the moment. – Lightness Races in Orbit Nov 17 '11 at 11:30
  • 1
    @TomalakGeret'kal What is your definition of STL? – David Rodríguez - dribeas Nov 17 '11 at 11:31
  • @DavidRodríguez-dribeas: http://www.sgi.com/tech/stl/ copyright HP 1994 - parts of the 1998 standard library were based on parts of this library. – Lightness Races in Orbit Nov 17 '11 at 11:32
  • 1
    @TomalakGeret'kal: See, the problem is that you only refer to the HP library as STL, but most people (including me) use the term to refer to the subset of the standard library that evolved from the STL proposal that Stepanov wrote for the committee (N0482) with that title. The standard does not mention STL, but it has become a *de-facto* standard for that subset of the library among most C++ programmers. What makes no sense at all is removing a widely used tag as STL from one question in favor of a different tag that most people will not understand/search for. – David Rodríguez - dribeas Nov 17 '11 at 11:40
  • @DavidRodríguez-dribeas: I'm sorry to hear that. I choose not to pander to misunderstandings (further fostering them). Your mileage is allowed to vary. – Lightness Races in Orbit Nov 17 '11 at 11:42
  • @DavidRodríguez-dribeas thanks for the edit. Just a comment: After the first edit LESS people clicked on my question. – cateof Nov 17 '11 at 11:43
  • @cateof: What? How can you _possibly_ correlate that? It's most likely complete nonsense. Bear in mind that the initial footfall on a question spikes for a minute or two after posting, because of its presence on the SO front page. My edit was *twenty-four minutes **after*** you posed the question, and you've only had a total of 53 views anyway -- hardly a viable statistical sample size. – Lightness Races in Orbit Nov 17 '11 at 11:43
  • @TomalakGeret'kal Do you know if 24 minutes after my question, it was removed from the front page? – cateof Nov 17 '11 at 11:46
  • @cateof: I can say with 100% certainty that your question will not have been on the front page for more than approximately five minutes, _at best_. The frequency of new questions on SO is enormous. – Lightness Races in Orbit Nov 17 '11 at 11:47
  • @DavidRodríguez-dribeas: I won't fight you on `stl` as I'm content with the tag wiki. – Lightness Races in Orbit Nov 17 '11 at 11:48
  • @cateof: I don't think that actually means anything, the people that have already read the question will not usually come back to it, and this is a very active page in that many people are *watching* changes in the main question page (or filtering by tags --I filter only questions with [c++] tag more often than not). Once someone has read the question, they will probably not come back. Additionally, I don't think that the stl/stdlib tags will make a huge difference today, but rather in the future when someone is searching (rather than browsing) – David Rodríguez - dribeas Nov 17 '11 at 11:52
  • the question is no problem: if an element is requested that doesn't exist, _no events_ (i.e. an empty vector) will be assigned by the default constructor of the value type, c.f. [this link](http://www.cplusplus.com/reference/stl/map/operator%5B%5D/) – moooeeeep Nov 17 '11 at 12:19

4 Answers4

4

Will inserting an empty vector do the trick?...

events.insert(std::make_pair("USA", std::vector<SomeClass>()));

You could then add actual events without checking of existence of map's value:

void event(const std::string& country, const SomeClass& data) {
    events[country].push_back(data);
}

I'm not sure whether this is what you're looking for, since the notion of 'creating "position" "USA"' looks ambiguous. (And earlier answers seem to pick different interpretation of it).

EDIT: As commenters pointed out, inserting the empty vector is not even necessary, since map values are automatically created (using default initializer) & inserted when one uses the [] operator. Hence you you can just do events["USA"].push_back(data) directly.

Xion
  • 22,400
  • 10
  • 55
  • 79
  • Exactly, this is what I was coming to depending on answer to my comment on the question above. – hmjd Nov 17 '11 at 10:20
  • @Xion, another trick would be to "add and remove" the dummy value. – cateof Nov 17 '11 at 10:21
  • 2
    The `event()` function would work already without the aforementioned insert. And the insert can be easier written as `events["USA"]` – PlasmaHH Nov 17 '11 at 10:23
  • @Xion what is the size of the vector after inserting? 0? – cateof Nov 17 '11 at 10:25
  • 1
    @cateof yes, the vector will be empty. – hmjd Nov 17 '11 at 10:32
  • I don't see the benefit of inserting empty vectors here - if you then call events.operator[] with a country not previously specified, it will still implicitly insert an empty vector. – themel Nov 17 '11 at 11:31
2

I think what you're looking for is std::multimap. This allows more than one value per key:

typedef std::multimap<std::string, SomeClass> EventMap;
typedef EventMap::value_type EntryType; // std::pair<..>

std::multimap<std::string, SomeClass> events;
// Add value
events.insert(std::make_pair("Norway", SomeClass(...)));

If you really need to be able mark a country as valid by inserting an empty placeholder I think that using a separate std::set probably would be a better solution. If you really want to do this, boost::optional or shared_ptr as mentioned by sehe is another solution.

larsmoa
  • 12,604
  • 8
  • 62
  • 85
2

Your question is somewhat unclear. You cannot insert a key without inserting a value as well. If this is really your intent, the answer is: No.

For your purpose I see no reason why you could not insert an empty vector instead (as others have pointed out). For actually doing this, you can do the insertion on initialisation of the map:

#include <string>
#include <map>
#include <initializer_list>
using namespace std;

class SomeClass { int x; };

int main() {
  SomeClass e1, e2, e3;
  map< string, vector<SomeClass> > events = // using initializer_list from c++0x  
  {
    {"USA",{e1,e2}}, {"CANADA",{ /* no events */ }, {"MEXICO",{e2,e3}}
  };
  // or later ...
  events["CUBA"] = {};
  events["RUSSIA"] = {e1,e2,e3};
}

Alternatively, you could return a default value if the key is not present when you ask for it, i.e. lazy initialization. The default behavior of the map is to add a new entry to the map using the default constructor of the value type whenever the requested key is missing. Which produces an empty vector<SomeClass> in this case. Therefore, I don't see what's wrong with this:

events["key that is missing beforehand"].push_back(e1);

If you actually want to avoid adding new entries to the map, you need to wrap your requests with something like:

string key = "USA";
vector<SomeClass> localEvents; // default, empty vector
// using the auto type from c++0x
auto ev = events.find(key);
if (ev == events.end()) // not found
  //events[key] = {}; // don't add the key to the map
  ;
else // get the corresponding vector
  localEvents = (*ev).second;

For this, you might also want to consider this related question: std::map default value

(The examples would work perfectly even without the c++0x features.)

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • then you will have to stick with the [old style initialisation](http://www.cplusplus.com/reference/stl/map/map/) of the map. – moooeeeep Nov 17 '11 at 12:06
1

The idiomatic solution(s) would be

typedef std::shared_ptr<SomeClass> element_t;
std::map<std::string, std::vector<element_t> >; 

Or

typedef boost::optional<SomeClass> element_t;
std::map<std::string, std::vector<element_t> > map; 

Then you could get it and use it like so:

if (map["USA"])
{
     SomeClass& use = *map["USA"];
     // ...
}
sehe
  • 374,641
  • 47
  • 450
  • 633