patterncppMinor
Type to instance map
Viewed 0 times
typeinstancemap
Problem
I needed a class where I could store an instance of any type. The goal was an interface as follows:
Such that:
Here is my solution:
```
#pragma once
// Note to CR.SO: Provides the ASSERT macro.
#include "assert.hpp"
#include
#include
//! A map of types to values.
//!
//! Associative container which allows mapping of types to values of that
//! type.
class TypeMap : boost::noncopyable {
template
class TypeMapDetail {
struct Node : boost::noncopyable {
Node(void key, Node parent) : key(key), lhs(), rhs(), parent(parent), data() {}
void* key;
Node* lhs;
Node* rhs;
Node* parent;
T data;
};
Node* root;
typedef void (destruct_func)(void);
static void destroy_impl(void* p) {
delete static_cast(p);
}
destruct_func destroy;
// No member data past this point.
Node& get_parent_to_this(Node current) {
if (!current->parent)
return root;
if (current->parent->lhs == current)
return current->parent->lhs;
else
return current->parent->rhs;
}
void remove_specific(Node* current) {
Node*& parent_to_this = get_parent_to_this(current);
if (!current->lhs && !current->rhs) {
parent_to_this = nullptr;
return;
}
if (!current->lhs) {
parent_to_this = current->rhs;
current->rhs->parent = current->parent;
return;
}
if (!current->rhs) {
parent_to_this = c
class TypeMap {
template
T& get();
};Such that:
- Iff
&m1 == &m2then&m1.get() == &m2.get().
- The first call to
m.getfor allm,Tcombinations returns a reference to a default-constructedT.
- A
TypeMapgoing out of scope deallocates all memory that was accessible through it.
Here is my solution:
```
#pragma once
// Note to CR.SO: Provides the ASSERT macro.
#include "assert.hpp"
#include
#include
//! A map of types to values.
//!
//! Associative container which allows mapping of types to values of that
//! type.
class TypeMap : boost::noncopyable {
template
class TypeMapDetail {
struct Node : boost::noncopyable {
Node(void key, Node parent) : key(key), lhs(), rhs(), parent(parent), data() {}
void* key;
Node* lhs;
Node* rhs;
Node* parent;
T data;
};
Node* root;
typedef void (destruct_func)(void);
static void destroy_impl(void* p) {
delete static_cast(p);
}
destruct_func destroy;
// No member data past this point.
Node& get_parent_to_this(Node current) {
if (!current->parent)
return root;
if (current->parent->lhs == current)
return current->parent->lhs;
else
return current->parent->rhs;
}
void remove_specific(Node* current) {
Node*& parent_to_this = get_parent_to_this(current);
if (!current->lhs && !current->rhs) {
parent_to_this = nullptr;
return;
}
if (!current->lhs) {
parent_to_this = current->rhs;
current->rhs->parent = current->parent;
return;
}
if (!current->rhs) {
parent_to_this = c
Solution
I don't see why you use
You could use a
I think I would approach the cleanup more like:
... which doesn't involve any of that
void as a key, when that pointer is always a TypeMap.You could use a
std::map as TypeMapDetail's member. (Yes, std::less is a safe total ordering, even though operator> is even easier.I think I would approach the cleanup more like:
class TypeMap : boost::noncopyable {
typedef void cleanup_func(TypeMap*);
template
class TypeMapDetail : boost::noncopyable {
static std::map > objects;
public:
static T& get(TypeMap*);
static void cleanup(TypeMap* tm) { objects.erase(tm); }
};
typedef std::map cleanup_map_type;
cleanup_map_type cleanup_actions;
public:
TypeMap() : cleanup_actions() {}
~TypeMap() {
for (cleanup_map_type::iterator iter = cleanup_actions.begin();
iter != cleanup_actions.end();
++iter) {
iter->second(this);
}
}
template
T& get() {
cleanup_actions.insert(std::make_pair(
std::cref(typeid(T)), &TypeMapDetail::cleanup));
return TypeMapDetail::get(this);
}
};... which doesn't involve any of that
static_cast undefined behavior at all. If C++11 is out, struct type_index is fairly easy to implement.Code Snippets
class TypeMap : boost::noncopyable {
typedef void cleanup_func(TypeMap*);
template<typename T>
class TypeMapDetail : boost::noncopyable {
static std::map<TypeMap*, std::unique_ptr<T> > objects;
public:
static T& get(TypeMap*);
static void cleanup(TypeMap* tm) { objects.erase(tm); }
};
typedef std::map<std::type_index, cleanup_func> cleanup_map_type;
cleanup_map_type cleanup_actions;
public:
TypeMap() : cleanup_actions() {}
~TypeMap() {
for (cleanup_map_type::iterator iter = cleanup_actions.begin();
iter != cleanup_actions.end();
++iter) {
iter->second(this);
}
}
template <typename T>
T& get() {
cleanup_actions.insert(std::make_pair(
std::cref(typeid(T)), &TypeMapDetail<T>::cleanup));
return TypeMapDetail<T>::get(this);
}
};Context
StackExchange Code Review Q#15316, answer score: 5
Revisions (0)
No revisions yet.