Указатели в качестве ключей в карте на C++ в STL
У меня есть вопрос о том, как обрабатываются указатели на пользовательский объект при использовании в качестве ключей в карте. Более конкретно, если я определяю
std::map< CustomClass*, int > foo;
Будет ли работать реализация C++ по умолчанию для обработки этих указателей? Или мне нужно определить пользовательскую функцию компаратора для ее обработки? Вообще, хорошо ли использовать указатели на объекты в качестве ключей?
5 ответов:
Реализация по умолчанию будет сравнивать адреса, сохраненные указателями, поэтому различные объекты будут рассматриваться как разные ключи. Однако логическое состояние объекта рассматриваться не будет. Например, если вы используете
std::string *в качестве ключа, два разных объектаstd::stringс одинаковым текстом"Hello"будут считаться разными ключами! (При хранении на карте по их адресам)Можно использовать указатели в качестве ключей, если вы понимаете важное различие выше.
Указатели будут обрабатываться, но сравниваться как указатели (порядок памяти). Вы должны передать пользовательский функтор
less, Если хотите сравнить объекты:template<class T> struct ptr_less { bool operator()(T* lhs, T* rhs) { return *lhs < *rhs; }}; map<Object*,int,ptr_less<Object>> mymap;
Стандарт C++ предусматривает специализацию
std::lessдля указателей, поэтому да, вы можете безопасно использовать их в качестве ключей карты и т. д.
Оставляя в стороне законность этого и любые возможные семантические недоразумения, уже рассмотренные, я не могу думать о какой-либо причине использовать
std::mapздесь, а неstd::unordered_map. Есть ранние перехваты этого в Boost и Visual C++, если вы находитесь на компиляторе до C++11.Поскольку вы, по-видимому, используете указатель для представления уникального объекта, что-то вроде boost::flyweight может быть применимо.
Указатели можно использовать в качестве ключей, но особенно с std:: map (или std:: set)я бы не советовал. поведение программы не является детерминированным, т. е. при итерации по карте порядок, в котором элементы на карте повторяются, не гарантируется одинаковым . Это действительно зависит от адреса памяти объекта (ключа). Взгляните на этот пример, как вы можете видеть, независимо от порядка вставки в карту элементы повторяются детерминированным образом, когда ключ является строкой, а не указателем.
#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; }
Comments