Подтвердить что ты не робот

Указатели как ключи на карте С++ STL

У меня возникает вопрос, как обрабатывать указатели на пользовательский объект при использовании в качестве ключей на карте. Более конкретно, если я определяю

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

Будет ли реализация С++ по умолчанию работать с этими указателями? Или мне нужно определить пользовательскую функцию компаратора для ее обработки? В общем, хорошо ли использовать указатели на объекты в качестве ключей?

4b9b3361

Ответ 1

Реализация по умолчанию будет сравнивать адреса, сохраненные указателями, поэтому различные объекты будут рассматриваться как разные ключи. Однако логическое состояние объекта не рассматривается. Например, если вы используете std::string * в качестве ключа, два разных объекта std::string с тем же текстом "Hello" будут считаться другим ключом! (При сохранении на карте по их адресам)

Хорошо использовать указатели в качестве ключей, пока вы понимаете важное различие выше.

Ответ 2

Указатели будут обрабатываться, но сравниваются как указатели (порядок памяти). Вы должны передать пользовательский less функтор, если хотите сравнить объекты:

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

Ответ 3

Стандарт С++ предоставил специализацию std::less для указателей, поэтому да, вы можете безопасно использовать их в качестве ключей карты и т.д.

Ответ 4

Оставив в стороне от законности этого и любых возможных семантических недоразумений, которые уже рассмотрены, я не могу думать о какой-либо причине использовать std::map здесь, а не std::unordered_map. Есть ранние перехваты этого в Boost и Visual С++, если вы находитесь в компиляторе pre-С++ 11.

Поскольку вы, кажется, используете указатель для представления уникального объекта, может быть применимо что-то вроде boost:: flyweight.

Ответ 5

Указатели могут использоваться как ключи, но особенно с 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;
}