Указатели в качестве ключей в карте на C++ в STL



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



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


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

797   5  

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)я бы не советовал. поведение программы не является детерминированным, т. е. при итерации по карте порядок, в котором элементы на карте повторяются, не гарантируется одинаковым . Это действительно зависит от адреса памяти объекта (ключа). Взгляните на этот пример, как вы можете видеть, независимо от порядка вставки в карту элементы повторяются детерминированным образом, когда ключ является строкой, а не указателем.

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

Comments

    Ничего не найдено.