gpt4 book ai didi

c++ - 将 shared_ptr 与通用注册表或共享对象存储一起使用......或不

转载 作者:行者123 更新时间:2023-11-30 03:44:28 25 4
gpt4 key购买 nike

免责声明;我知道这不是很漂亮...

所以,我想要一个注册表或共享对象存储,用于全局、共享、各种不同类(子系统、管理器等)的实例我不想为此使用单例,我希望能够有一个简单的注册表,我可以在其中针对 key 注册任何实例,然后稍后获得该实例的 shared_ptr。

通过使用可疑的转换、原始字节 View 和不正当的强制转换,我设法创建了一个可以执行此操作并且有效的类(至少在 VS 2015 中)。

我可以做这样的事

myRegistry->add<FooType>(1,2,3);
....
auto shared_foo_ptr = myRegistry->get<FooType>();

这很可爱,但当然,引擎盖下的代码有异味。

或者是吗?

在这里,我真的很想要一些评论和建设性的撕碎;

 class Registry {

struct reg_shared_ptr_item {
// raw byte storage for a shared_ptr of any type (assuming they are always the same size)
char _storage[sizeof(std::shared_ptr<reg_shared_ptr_item>)];
// the deleter will be bound to the correctly typed destructor of the original share_ptr
std::function<void(reg_shared_ptr_item&)> _deleter;
};

/**
this union is used to get access to the raw bytes of a pointer-to-member
since these can't be cast to anything directly
**/
union fptr_hasher {
char _raw[sizeof(&std::shared_ptr<Registry>::use_count)];
uint64_t _key_bits;
};

template<typename T>
static uint32_t get_key_for_type() {
// C++ disallows converting a pointer-to-member to a void* or any other normal pointer
// but we don't really need that, we just need the bits which will be unique since each type
// has it's own implementation
// NOTE: if the compiler for some reason or other chooses to be clever about instantiation and
// it doesn't actually create a new instance for each type then this will cause collisions
typedef long (std::shared_ptr<T>::*fptr_t)(void) const;
fptr_hasher hasher;
// create a pointer-to-member instance over the union so that we get access to the raw bytes
fptr_t* fptr = ::new(&hasher) fptr_t;
*fptr = &std::shared_ptr<T>::use_count;
return (reg_key_t)hasher._key_bits;
}

public:

typedef uint32_t reg_key_t;

Registry() = default;
~Registry() {
// clean up; invoke the type-bound destructors
for (auto& kv : _reg_map) {
kv.second._deleter(kv.second);
}
}

template<typename T, class...Args>
bool add(Args&&...args) {

auto key = get_key_for_type<T>();
auto found = _reg_map.find(key);
if (found == _reg_map.end()) {
// first; initialise the raw memory location to be a proper shared_ptr
reg_shared_ptr_item entry;
::new(entry._storage) std::shared_ptr<T>();
// create-assign a new shared_ptr instance
auto sas = reinterpret_cast<std::shared_ptr<T>*>(entry._storage);
*sas = std::make_shared<T>(args...); //< at this point the instance count is 1
// store off f-pointer to a properly typed destructor
entry._deleter = [](reg_shared_ptr_item& item) {
reinterpret_cast<std::shared_ptr<T>*>(item._storage)->~shared_ptr<T>();
};
_reg_map.emplace(key,entry);
return true;
}
return false;
}

template<typename T>
std::shared_ptr<T> get() const {
auto key = get_key_for_type<T>();
auto found = _reg_map.find(key);
if (found != _reg_map.end()) {
return *(reinterpret_cast<std::shared_ptr<T>*>(const_cast<char*>(found->second._storage)));
}
return nullptr;
}

template<typename T>
static reg_key_t getHash() {
return get_key_for_type<T>();
}

private:
typedef std::map<reg_key_t, reg_shared_ptr_item> reg_map_t;
reg_map_t _reg_map;
};

最佳答案

你可以使用 std::type_index作为关键,shared_ptr<void>作为类型删除存储。也许沿着这些思路(demo):

class Registry {
std::map<std::type_index, std::shared_ptr<void> > registry_;
public:
template<typename T, class...Args>
bool add(Args&&...args) {
std::type_index key(typeid(T));
if (!registry_.count(key)) {
auto p = std::make_shared<T>(std::forward<Args>(args)...);
registry_[key] = p;
return true;
}
return false;
}

template<typename T>
std::shared_ptr<T> get() const {
auto it = registry_.find(typeid(T));
if (it == registry_.end()) {
return std::shared_ptr<T>();
}
return std::static_pointer_cast<T>(it->second);
}
};

关于c++ - 将 shared_ptr 与通用注册表或共享对象存储一起使用......或不,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35413745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com