Умные указатели как unordered_map key и сравнивают их по ссылке - PullRequest
0 голосов
/ 30 октября 2018

Я хочу использовать unordered_map для сравнения элементов по ссылке. Я попытался сделать это, вставив умные указатели в качестве ключа (поскольку я не хочу использовать необработанные указатели), и реализовал EqualFunction для сравнения базовых ссылок умных указателей. Однако карта не может правильно найти элементы.

#include <memory>
#include <unordered_map>
#include <iostream>

using namespace std;

class Node {};

typedef shared_ptr<Node> NodePtr;

struct HashFunction {
    unsigned long operator()(const NodePtr& key) const {
        return (unsigned long)key.get();
    }
};

struct EqualFunction {
    bool operator()(const NodePtr& t1, const NodePtr& t2) const {
        return t1.get() == t2.get();
    }
};

class Map
{
    unordered_map<NodePtr, int, HashFunction, EqualFunction> map;
public: 
    void insert(NodePtr nodeToInsert, int val)
    {
        map.insert({nodeToInsert, val });
    }

    bool exist(NodePtr node) {
        if (map.find(node) == map.end()) return false;
        return true;
    }
};

int main()
{
    Node node; Map map;
    auto nodePtr = make_shared<Node>(node);
    map.insert(nodePtr, 1);
    auto ptrToSameNode = make_shared<Node>(node);
    if (map.exist(ptrToSameNode)) 
        cout << "Node exists.";
        else cout << "Node doesn't exist.";
}

Выше кода печатается «Узел не существует», даже если я ищу тот же узел.

1 Ответ

0 голосов
/ 30 октября 2018

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

using NodePtr = Node*;

struct HashFunction {
  size_t operator()(const NodePtr& key) const { return (size_t)key; }
};

struct EqualFunction {
  bool operator()(const NodePtr& t1, const NodePtr& t2) const { return t1 == t2; }
};

...

int main()
{
  Node node; Map map;
  auto nodePtr = &node;
  map.insert(nodePtr, 1);
  auto ptrToSameNode = &node;
  if (map.exist(ptrToSameNode)) 
    cout << "Node exists.";
    else cout << "Node doesn't exist.";
}

Как писал @Piotr Skotnicki в комментарии, проблема заключалась в том, что вы изначально создали 3 Node объекта, то есть node плюс 2 динамически размещенных объекта, которые скопировали node (через make_shared). Поэтому вы сравнили (по адресу) 2 разных экземпляра класса Node.


В качестве альтернативы вы можете использовать общие указатели , но тогда вам нужно динамически создавать Node объекты (а не статически в стеке, как в вашем коде). Вы также можете использовать слабые указатели , если вы не хотите, чтобы ваш Map "владел" включенными объектами, но тогда ваше сравнение будет медленнее (выполняется с помощью "блокировки", то есть создания общих указателей). образуют слабые) и будет много времени выполнения и нехватки памяти.

...