2

Let's assume there are 2 classes: Country and City. Both of them have names, so a map would suit as conainer

map<std::string, Country> countries;

In the country class there is a similar map that contains all cities - for the sake of simplicity, let's say it's public:

map<std::string, City> cities;

Now on top level if a specific city should be addressed, the request looks like this:

countries.at("Japan").cities.at("Tokyo");

(In the real world I should rather use find and check every time if the desired country/city does actually exist, right?)

Now let's say at top level we want to store in a vector a set of our favourite cities. I see 2 options to do so:

// Option 1: Store the cities as references: 
vector<City&> favouriteCities;

// Option 2: Store the ID's (Names) of the countries and the cities as strings
vector<pair<std::string,std::string>> favouriteCities;

So to get my first favourite city in option 2 I'll have to access it like this:

countries.at(favouriteCities[0].first).cities.at(favouriteCities[0].second);

What would be the pros and cons of these options? AFAIK: Option 1 is more performant and more convenient. But with option 2 you have te chance to check if the desired favourite city is still in the system and has not been deleted in the meantime (so a reference would be invalid).

Are there more points to consider?

  • 2
    The problem you are presenting, the reference to a deleted content, is directly tied to multi directional flow. You are removing an item and it is your responsibility to update all the components which use it. In a uni directional application architecture all your actions are dispatched using a dispatcher which then makes the updating of connected components clearer. – Andy Mar 8 '16 at 13:08
3

Option 2 is definitely best.

The main con of option 1 is that it is impossible; standard containers may not contain references.

Though you could "fake" it using std::ref, storing handles to container elements is never a good idea anyway. What happens when those elements are invalidated by map erasure? At worst you want a std::unique_ptr, and at best you want to make use of the convenient string keys you already use.

If you discover (through profiling!) that the string comparisons are a bottleneck, only then consider implementing something a more complex, more "algorithmic" solution.

| improve this answer | |
  • Thanks for your analysis. Also thanks for pointing out that references are not storeable in vectors - I edited the original post accordingly. – Stefan Woehrer Mar 8 '16 at 14:16
  • @StefanWoe: It would be appreciated if you didn't edit the answers into the question! – Lightness Races in Orbit Mar 8 '16 at 14:30
  • Ok, changed it back to the original. Thanks for the advice. However, the base question remains the same: (wrapped) reference vs. string lookup :) – Stefan Woehrer Mar 8 '16 at 14:46
  • @StefanWoe: Yepper :) – Lightness Races in Orbit Mar 8 '16 at 14:56
1

Instead of a simple reference, you could store a shared_ptr of the City or Country, then it can be removed from the map and still exist in memory (ie while it is still favourited). It'll only be deleted from memory when all references are removed.

Alternatively, you can store the City and Country entries in a container (eg a vector so you gain from a contiguous block of storage) specifically to hold them, and have both favourites and map point to these initial entries - a bit like a very high-level "malloc and pointer" approach. The concept is that you have 1 entity that holds ownership of the objects, and everything else can then simply refer or point to them without any worries over ownership and object lifetimes.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.