std::map 的键是指针取消引用指针吗?还是需要自定义比较器?

问题描述 投票:0回答:6

我有一个关于在映射中用作键时如何处理指向自定义对象的指针的问题。更具体地说,如果我定义

std::map< CustomClass*, int > foo;

默认的 C++ 实现可以处理这些指针吗?或者我是否需要定义一个自定义比较器函数来处理它?一般来说,使用对象指针作为键是一个好的做法吗?

c++ pointers dictionary stl
6个回答
87
投票

默认实现会比较指针存储的地址,因此不同的对象将被视为不同的键。但是,不会考虑对象的逻辑状态。例如,如果您使用

std::string *
作为键,则两个具有相同
std::string
文本的不同
"Hello"
对象将被视为不同的键! (按地址存储在地图中时)

只要您理解上面的重要区别,就可以使用指针作为键。


37
投票

指针将被处理,但作为指针进行比较(内存顺序)。如果您想比较对象,您必须传递自定义

less
函子:

template<class T> struct ptr_less 
{
    bool operator()(T* lhs, T* rhs) 
    {
        return *lhs < *rhs; 
    }
};
map<Object*, int, ptr_less<Object>> myMap;

11
投票

C++ 标准为指针提供了

std::less
的专门化,所以是的,您可以安全地将它们用作映射键等。


6
投票

除了已经解决的合法性和任何可能的语义误解之外,我想不出任何理由在这里使用

std::map
而不是
std::unordered_map
。 如果您使用的是 C++11 之前的编译器,则 Boost 和 Visual C++ 中对此有早期拦截。

由于您似乎使用指针来表示唯一对象,因此诸如 boost::flyweight 之类的内容可能适用。


6
投票

指针可以用作键,但特别是对于 std::map (或 std::set),我不建议这样做。 程序的行为不是确定性的,即当迭代映射时,不能保证迭代映射中的项目的顺序是相同的。它实际上取决于对象(键)的内存地址。看一下这个示例,您可以看到,无论映射中的插入顺序如何,当键是字符串而不是指针时,项目都会以确定性方式迭代。

http://ideone.com/VKirct

#include <iostream>
#include <map>
using namespace std;

class SomeClass {
    public:
    SomeClass(const std::string& name): m_name(name) {}
    std::string GetName()const {return m_name; }
    bool operator <(const SomeClass& rhs) const { return m_name < rhs.m_name; }
    private:
    std::string m_name;
};

auto print_seq  = [](const auto& seq) { for (const auto& itr: seq) {std::cout << itr.second << " , ";} std::cout << std::endl;};

int main() {
    // your code goes here
    std::map<SomeClass*, std::string> pointer_keyed_map;
    SomeClass s3("object3");
    SomeClass s1("object1");
    SomeClass s2("object2");
    pointer_keyed_map.insert(std::make_pair(&s1, s1.GetName()));
    pointer_keyed_map.insert(std::make_pair(&s2, s2.GetName()));
    pointer_keyed_map.insert(std::make_pair(&s3, s3.GetName()));
    std::cout << "Pointer based keys: object order" << std::endl;
    print_seq(pointer_keyed_map);

    std::map<SomeClass, std::string> int_keyed_map;
    int_keyed_map.insert(std::make_pair(s3, s3.GetName()));
    int_keyed_map.insert(std::make_pair(s1, s1.GetName()));
    int_keyed_map.insert(std::make_pair(s2, s2.GetName()));
    std::cout << "String based keys: object order" << std::endl;
    print_seq(int_keyed_map);
    return 0;
}

0
投票

这样做是可以的,但似乎没有意义。
我的意思是map或者set存储对象只要对象不同,但是存储指针之后可能会造成不稳定的问题,因为指针没有任何意义,有意义的是指针所在地址存储的值指向,所以最好编写一些比较函数来比较对象中的值。 不是对象的地址。

© www.soinside.com 2019 - 2024. All rights reserved.