-1

I find some of the std::map<> reference material a little difficult to understand at times.

  1. When I add an object to the map, does it copy that object like MFC's CMap<> does? Or does it then own the object I added?

  2. I'm trying to create a custom comparer. However, my key is a class type. How do I specify that the comparer should be passed a reference to the key object rather than the object itself? Or would declaring my comparer as receiving a reference suffice?

melpomene
  • 84,125
  • 8
  • 85
  • 148
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • What would it mean to "own the object I added"? – melpomene Aug 11 '19 at 07:16
  • @melpomene: It would mean that I don't need to (and shouldn't) free the object and that `std::map` will do that when it no longer needs the object. It also means I must new up any object that I add to the map rather than reusing an existing object. The only other option I can think of is that it will call my `operator=` method to copy it to its own memory. – Jonathan Wood Aug 11 '19 at 07:22
  • @melpomene: You voted to close the question? – Jonathan Wood Aug 11 '19 at 07:29
  • Yes, once I realized I could answer #1 but not #2. They're really two distinct questions, i.e. "too broad". – melpomene Aug 11 '19 at 07:30

2 Answers2

1

I'm not sure I'm fully understand what you want to know,but let me try to share my experiance.

  1. if "Own the object" mean's copy the value to map's own memory space, It's yes. insert one item to std::map<int, Object>, will takes at least size(pair<int, Object>) memory, and auto destroy them when erased. (ignoring stl's memory allocator buffer)

    If you want "A reference", consider use std::shared_ptr<Object> instead. It takes only one memory space , and destroyed when all reference is released.

    ps: detailed map's memory: How can i estimate memory usage of std::map?

  2. Comparer function accepts reference value, you should use this in most cases.

Example

class CObjectKey
{
public:
    CObjectKey(int type, int index)
        : type_(type), index_(index)
    {
    }

    bool operator <(const CObjectKey& right) const
    {
        if (this == &right)return false;
        return (type_ < right.type_) || (type_ == right.type_ && index_ < right.index_);
    }
private:
    int type_;
    int index_;
};

int main()
{
    std::map<CObjectKey, std::string> map1;
    map1.emplace(CObjectKey(1, 2), "val_1_2");
    map1.emplace(CObjectKey(1, 3), "val_1_3");
    std::cout << "Hello World! " << map1[CObjectKey(1,3)] << std::endl;
}
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
wwc
  • 101
  • 6
  • No, I'm okay if it copies the object. I find that a bit inefficient in some cases, but it simplifies a lot of things. – Jonathan Wood Aug 11 '19 at 07:35
  • emm... In my project, to avoid copying object, the most difficult thing is to maintain it's life time through multiple thread. – wwc Aug 11 '19 at 08:03
  • And thanks to edit the format error. I'm not so familiar with stackoverflow's edit function. – wwc Aug 11 '19 at 08:05
1

All objects contained in a std::map (or any other standard container, for that matter) have their lifetimes managed by the container. Containers contain objects. If you want a container to contain pointers you would need to declare it as such.

For example in the following code,

struct MyType { /*...*/ };
MyType my_object;
std::map<int, MyType> my_map;
my_map.insert({42, my_object});

a copy of my_object is made, but in the following

struct MyType { /*...*/ };
MyType my_object;
std::map<int, MyType*> my_map;
my_map.insert({42, &my_object});

the only thing that gets copied is a pointer to my_object, not my_object itself. In this case, the map still manages the lifetimes of its contained objects, but those contained objects are only pointers, and you are responsible for making sure the pointed-to objects outlive the pointers to them. The best way to do that is usually to use one of the standard smart pointer class templates: either std::unique_ptr or std::shared_ptr, depending on your needs.


For the second part of you question, yes, just having your custom comparator accept values by reference is enough. std::map passes the actual objects contained in it to the comparator.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52