1

I wanted to defined a map like std::unordered_map<int, std::unordered_set<int>> or std::unordered_map<int, std::unique_ptr<std::unordered_set<int>>>

I am not sure which one is better.

I cannot see if the first one has any problem. In terms of Does std::map::iterator return a copy of value or a value itself? the first is safe because the access of each set of a map should also be of reference type.

If so, which one is better?

Community
  • 1
  • 1
Joe C
  • 2,757
  • 2
  • 26
  • 46
  • 3
    It really depends what you want. There's no "problem" with either of them, but they mean different things. – Greg Hewgill Sep 02 '15 at 00:51
  • I guess the only thing that the second type can do is releasing the memory of a set and passing it to others. If the map is the only owner of all the sets, functionally they should be same. But I am not sure in terms of the time/space performance, is there any con/pro of each definition? – Joe C Sep 02 '15 at 00:54
  • Both look good, but unless I have a good reason to add the complexity of a pointer, even a safe one, I shy away from it. – user4581301 Sep 02 '15 at 00:55
  • 1
    I recommend keeping it simple until you know there's a reason to do otherwise. Using the additional indirection of `unique_ptr` is unnecessary if you're not sure why you'd want it. Historically, many of the reasons that might have caused you to choose the `unique_ptr` approach are now solved by move-semantics. – paddy Sep 02 '15 at 00:56
  • 1
    They both do the essentiallysame thing. The first one is better because its less complicated. In either one the `std::unordered_set` uses a *pointer* internally and stores its data on the heap (free-store). `STL` containers are basically smart pointers managing their data through *pointers*. – Galik Sep 02 '15 at 00:58
  • @paddy, I think what you mean is 'most of the reasons... choose a UNIQUE pointer are now ... by move-semantics'? – Joe C Sep 02 '15 at 00:58
  • @JoeC Cheers, fair enough. I had time to edit my comment. Although, it feels weird because `std::unique_ptr` was added at the same time as move semantics. But yes, the concept of unique pointers itself was around for much longer and that's what I was getting at. – paddy Sep 02 '15 at 01:02

3 Answers3

1

I would prefer std::unordered_map<int, std::unordered_set<int>>. Most C++ containers consist of a kind of 'header' data structure, containing pointers to the actual data (e.g. an std::vector is simply a class containing a few pointers to the actual underlying 'array' data). This 'header' data structure is typically relatively small, so if you would store an std::unique_ptr to it, the actual overhead of the memory allocation (both in CPU-time overhead and memory overhead) will be relatively large.

On the other hand, if your problem requires you to efficiently see that an entry in the std::unordered_map is 'empty', and/or you will have lots of these empty entries in the map, using an std::unique_ptr might be more efficient.

Also note that containers like std::set and std::map have a relatively large memory overhead. Consider using std:vector instead of std::set if the set would only contain a few elements. Looping over a small vector to check for duplicates might be more efficient that using the hashing logic of an std::set (because the memory locality of the std::vector will make more efficient use of the processors memory cache, see presentation of Chandler Carruth on CPPCON2014, https://www.youtube.com/watch?v=fHNmRkzxHWs).

Patrick
  • 23,217
  • 12
  • 67
  • 130
0

You need to define your utility function if you want to know what is best.

What are you optimizing? As the question stands, I can just say that personally, I prefer less typing so std::unordered_map<int, std::unordered_set<int>> is best. But, that's likely not your utility function.

If you are concerned about performance, then if you use std::unique_ptr the extra level of indirection will cost you, an allocation, a hop and a cache load. If you were sharing sets between collections, then a std::shared_ptr would cost a hop but maintain consistency and lower overall memory.

If your sets are smallish, frequently empty, or updated often, it might make sense to use std::unordered_map<int,std::set<int>>

Under some use cases you could also combine the map and set keys and just use std::unordered_set<std::pair<int, int> >

Or std::tuple<int, int> if supported.

Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
  • My concern was more about runtime efficiency. In terms of all above answers, they should be the same about performance. Than the first one gives us less typing. – Joe C Sep 02 '15 at 11:25
  • @JoeC you should refine your question to include your utility function, and state your use case, but in the meantime, see if my edit helps you – Glenn Teitelbaum Sep 02 '15 at 15:33
0

std::unordered_map<int, std::unique_ptr<std::unordered_set<int>>>
this looks really redundant. the whole point of unique_ptr is that when it gets out of scope - it deletes and destroy what it points at.
if your map's value is some pointer that needs deletion - go ahead. but your value is std::unordered_set that will get destroyed and deleted even without the pointer.
so you basically add extra creation and deletion on the smart pointer without adding any extra functionality.

David Haim
  • 25,446
  • 3
  • 44
  • 78