Reputation: 3
Problem Statement: Iterate over an array of objects and check if the object exists in an unordered_set.
Goal: I could have thousand of objects in one container to check their existence in millions of objects in another container. I choose unordered_set for its constant finding complexity and vector for iterating. I'm new to this and if you have any alternate approach, I'd really appreciate it.
Issue: unordered_set find isn't working as expected or I got the concept wrong!
Main:
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";
}
}
}
Block Class Overload:
bool Block::operator==(std::unique_ptr<Block>& block) const {
return block->getName() == mName;
}
Expected Output:
mod1
mod2
Block:
#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;
};
Upvotes: 0
Views: 604
Reputation: 94
The problem there is that you are trying to compare pointers, which are different! I'dont know the reasons behind using unique_ptr<> but by doing that you are actually trying to compare identities, instead of states which is what you want.
So you can see what I mean, let's say the first Block object is at position 100 in your memory. That would be its identity. So we have object1 whose state is "mod1, work" and whose identity is 100. Then we have object2, whose identity is 150 but its state is the same as object1, "mod1, work".
All what you have both inside the vector and the unordered_set are pointers, so you have memory positions. When inserting them in the vector, you inserted, let's say, position 100. But in the unordered_set you inserted 150. They have the same state, but find method is looking for a memory position.
I hope my answer was helpful. If you find any mistakes here or think differently please let me know. Good luck! :)
Upvotes: 0
Reputation: 366
You are trying to compare pointers, not values.
You need to specify hashing function for class Block
.
For example, if you want to use mName as key the code will be the following:
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";
}
}
}
Upvotes: 2
Reputation: 182827
An unordered_set
requires a hashing function and a comparison function. You are using the existing hashing and comparison functions for std::unique_ptr
, which is definitely not what you want.
I would not suggest trying to change the behavior of std::unique_ptr<Block>
because that will lead to confusion in other code that wants normal semantics for pointers. Instead, add normal hashing and comparison functions for Block
and pass customized ones to the constructor of the unordered_set
.
Upvotes: 2