我有一个问题,当在地图中用作键时,如何处理指向自定义对象的指针。更具体地说,如果我定义
std::map< CustomClass*, int > foo;
默认的C ++实现是否可以处理这些指针?或者我是否需要定义自定义比较器函数来处理它?通常,将对象指针用作键是一种好习惯吗?
答案 0 :(得分:48)
默认实现将比较指针存储的地址,因此不同的对象将被视为不同的键。但是,不会考虑对象的逻辑状态。例如,如果您使用std::string *
作为键,则具有相同文本std::string
的两个不同"Hello"
对象将被视为不同的键! (按地址存储在地图中时)
只要你理解上面的重要区别,就可以使用指针作为键。
答案 1 :(得分:20)
指针将被处理,但作为指针(内存顺序)进行比较。如果要比较对象,则必须传递自定义less
仿函数:
template<class T> struct ptr_less {
bool operator()(T* lhs, T* rhs) {
return *lhs < *rhs; }};
map<Object*,int,ptr_less<Object>> mymap;
答案 2 :(得分:7)
C ++标准为指针提供了std::less
的特化,所以是的,你可以安全地将它们用作地图键等。
答案 3 :(得分:3)
除了这个的合法性以及已经解决的任何可能的语义误解外,我想不出有任何理由在std::map
而不是std::unordered_map
使用{{1}}。如果您使用的是C ++ 11之前的编译器,可以在Boost和Visual C ++中进行早期的截获。
由于您似乎使用指针来表示唯一对象,因此boost::flyweight之类的内容可能适用。
答案 4 :(得分:3)
指针可以用作键,但特别是std :: map(或std :: set)我不会建议它。 程序的行为不是确定性的,即当一个人在地图上迭代时,地图中的项目被迭代的顺序不能保证是相同的。它实际上取决于对象(key)的内存地址。看一下这个例子,正如你所看到的那样,无论插入到地图中的顺序如何,当键是字符串而不是指针时,项目将以确定的方式迭代。
#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;
}