Невозможно найти пользовательский тип в неупорядоченном наборе c ++ с пользовательским оператором == () - PullRequest
0 голосов
/ 26 февраля 2020

Постановка задачи: Перебрать массив объектов и проверить, существует ли объект в unordered_set.

Цель: Я мог бы иметь тысячи объектов в одном контейнере, чтобы проверить их существование в миллионах объектов в другом контейнере. Я выбираю unordered_set для его постоянной сложности поиска и вектор для итерации. Я новичок в этом, и если у вас есть альтернативный подход, я бы очень признателен.

Проблема: unordered_set find не работает, как ожидалось, или я ошибся!

Основной:

int main() {
  std::vector<std::unique_ptr<Block>> vertices;

  vertices.push_back(std::make_unique<Block>("mod1", "work"));
  vertices.push_back(std::make_unique<Block>("mod2", "work"));
  vertices.push_back(std::make_unique<Block>("mod3", "work"));

  std::unordered_set<std::unique_ptr<Block>> undefs;

  undefs.insert(std::make_unique<Block>("mod1", "work"));
  undefs.insert(std::make_unique<Block>("mod2", "work"));

  for(auto& vertex : vertices) {
    auto search = undefs.find(vertex);
    if(search != undefs.end()){
      std::cout << "Block: " << vertex->getName() << "\n";
    }
  }
}

Перегрузка класса блока:

bool Block::operator==(std::unique_ptr<Block>& block) const {
  return block->getName() == mName;
}

Ожидаемый выход:

mod1

mod2

Блок:

#pragma once

#include <string>
#include <memory>

using std::string;

class Block {
  private:
    string mName;
    string mLib;
  public:
    Block(string const& name, string const& lib);
    string getName() const;
    string getLib() const;
    bool operator==(std::unique_ptr<Block>& block) const;
};

Ответы [ 3 ]

2 голосов
/ 27 февраля 2020

Вы пытаетесь сравнивать указатели, а не значения. Для класса Block.

необходимо указать функцию хеширования. Например, если вы хотите использовать mName в качестве ключа, код будет следующим:

class Block {
private:
    string mName;
    string mLib;
public:
    Block(string const& name, string const& lib)
    {
        mName = name;
        mLib = lib;
    }
    string getName() const {
        return mName;
    };
    string getLib() const {
        return mLib;
    }
    bool operator==(const Block & block) const;
};

template<> struct std::hash<Block> {
    std::size_t operator()(const Block & block) const noexcept {
        return std::hash<std::string>{}(block.getName());
    }
};

bool Block::operator==(const Block & block) const {
    return block.getName() == mName;
}

int main() {
    std::vector<Block> vertices;

    vertices.emplace_back(Block("mod1", "work"));
    vertices.emplace_back(Block("mod2", "work"));
    vertices.emplace_back(Block("mod3", "work"));

    std::unordered_set<Block> undefs;
    undefs.emplace(Block("mod1", "work"));
    undefs.emplace(Block("mod2", "work"));

    for (auto& vertex : vertices) {
        auto search = undefs.find(vertex);
        if (search != undefs.end()) {
            std::cout << "Block: " << vertex.getName() << "\n";
        }
    }
}
2 голосов
/ 26 февраля 2020

Для unordered_set требуется функция хеширования и функция сравнения. Вы используете существующие функции хеширования и сравнения для std::unique_ptr, что определенно не то, что вам нужно.

Я бы не советовал пытаться изменить поведение std::unique_ptr<Block>, потому что это приведет к путанице в другом коде это хочет нормальную семантику для указателей. Вместо этого добавьте обычные функции хеширования и сравнения для Block и передайте пользовательские функции конструктору unordered_set.

0 голосов
/ 27 февраля 2020

Проблема в том, что вы пытаетесь сравнить указатели, которые отличаются! Я бы не знал причин использования unique_ptr <>, но при этом вы фактически пытаетесь сравнить тождества, а не состояния, что вам и нужно.

Итак, вы можете понять, что я имею в виду, скажем, первое Блок-объект находится в позиции 100 в вашей памяти. Это было бы его личность. Таким образом, у нас есть объект1, чье состояние «mod1, работа» и чья идентичность 100. Затем у нас есть объект2, чья идентичность 150, но его состояние совпадает с object1, «мод1, работа».

Все что у вас есть как внутри вектора, так и unordered_set являются указателями, поэтому у вас есть позиции в памяти. Вставляя их в вектор, вы вставили, скажем, позицию 100. Но в unordered_set вы вставили 150. У них такое же состояние, но метод find ищет позицию в памяти.

Я надеюсь, что мой ответ было полезно. Если вы обнаружите здесь какие-либо ошибки или думаете иначе, пожалуйста, дайте мне знать. Удачи! :)

...