I\'m trying to use both a list and an unordered_map to store the same set of objects. I\'m new to C++, so still getting comfortable with iterators.
Say I have the follow
While Barry's approach is good, there is another one, more advanced and complicated. You can put your data object, (integer) key, and all bookkeeping bits in a single chunk of memory. Thus data locality will be improved and pressure on memory allocator will be less. Example, using boost::intrusive
:
#include
#include
#include
using namespace boost::intrusive;
class Foo {
// bookkeeping bits
list_member_hook<> list_hook;
unordered_set_member_hook<> set_hook;
const int key;
// some payload...
public:
// there is even more options to configure container types
using list_type = list, &Foo::list_hook>>;
using set_type = unordered_set, &Foo::set_hook>>;
Foo(int key): key(key) {};
bool operator ==(const Foo &rhs) const {
return key == rhs.key;
}
friend std::size_t hash_value(const Foo &foo) {
return std::hash()(foo.key);
}
};
class Bar {
Foo::list_type list;
std::array buckets;
Foo::set_type set{Foo::set_type::bucket_traits(buckets.data(), buckets.size())};
public:
template
Foo &emplace(Args&&... args) {
auto foo = new Foo(std::forward(args)...);
// no more allocations
list.push_front(*foo);
set.insert(*foo);
return *foo;
}
void pop(const Foo &foo) {
set.erase(foo);
list.erase(list.iterator_to(foo));
// Lifetime management fun...
delete &foo;
}
};
int main() {
Bar bar;
auto &foo = bar.emplace(42);
bar.pop(foo);
}
Measure how good are both algorithms on your data. My idea may give you nothing but greater code complexity.