向 std::map<> 添加对象和自定义比较

Adding objects to, and custom comparisons for std::map<>

我发现某些 std::map<> 参考 material 有时有点难以理解。

  1. 当我向地图添加一个对象时,它会像 MFC 的 CMap<> 那样复制该对象吗?或者它是否拥有我添加的对象?

  2. 我正在尝试创建自定义比较器。但是,我的密钥是 class 类型。我如何指定应该向比较器传递对关键对象而不是对象本身的引用?或者将我的比较器声明为接收参考就足够了吗?

我不确定我是否完全理解你想知道的,但让我尝试分享我的经验。

  1. 如果"Own the object"意思是将值复制到map自己的内存中space,是的。 向 std::map 插入一个项目,将至少占用 size(pair) 内存,并在擦除时自动销毁它们。 (忽略stl的内存分配缓冲区)

    如果您需要 "A reference",请考虑改用 std::shared_ptr。它只占用一个内存 space ,并在所有引用被释放时销毁。

    ps:详细图的内存:How can i estimate memory usage of std::map?

  2. 比较函数接受参考值,大多数情况下你应该使用它。

  3. 例子

    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;
    }
    

    std::map(或任何其他标准容器)中包含的所有对象的生命周期都由容器管理。容器包含对象。如果您希望容器包含指针,您需要这样声明它。

    例如在下面的代码中,

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

    复制了my_object,但在下面

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

    唯一被复制的是指向 my_object 指针 ,而不是 my_object 本身。在这种情况下,地图仍然管理其包含对象的生命周期,但那些包含的对象只是指针,您有责任确保指向的对象比指向它们的指针更长寿。最好的方法通常是使用标准智能指针 class 模板之一:std::unique_ptrstd::shared_ptr,具体取决于您的需要。


    对于你问题的第二部分,是的,只要让你的自定义比较器通过引用接受值就足够了。 std::map 将其中包含的实际对象传递给比较器。