我应该如何在工厂 class 中存储弱指针列表?
How should I store a list of weak pointers in the factory class?
我的项目中有一个Factoryclass,如果调用了Create
方法,就是returnsstd::shared_ptr<MyClass>
。工厂不是所有者,但它维护一个已创建对象的列表。有时工厂需要遍历仍在使用的已创建对象,或者对它们进行计数。
我使用 std::vector<std::weak_ptr<MyClass>>
实现了这个。迭代看起来像这样:
for (std::weak_ptr<MyClass> wp : weak_list) {
if (auto sp = wp.lock()) {
//..
}
}
Create
函数:
std::shared_ptr<MyClass> Create(/* ... */) {
std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
//...
weak_list.push_back(obj);
return obj;
}
vector 是像这样的列表的最佳容器吗?也许 std::set
会更好。
如果我使用向量实现它,我必须定期检查列表中的过期指针并将其删除
在工厂中存储弱指针列表的首选方法是什么class?
默认使用矢量。
Sets不会自行清理过期指针,手动清理过程相同。
考虑在迭代之前清除死元素,并迭代弱列表的副本(以防迭代改变弱列表)。
如果您需要立即清除悬挂的弱指针,请修改共享指针以在最后一个强引用消失时从弱列表中注销自身。这需要一些与 make shared 有关的工作,包括对齐存储、手动构建和销毁、辅助结构和共享 ptr 的别名构造器。
template<class T>
struct shared_helper {
typename std::aligned_storage<sizeof(T),alignof(T)::type data;
T* get(){ return reinterpret_cast<T*>(&data); }
bool constructed = false;
weak_list<T>* list=0;
std::weak_ptr<T> self;
~shared_helper(){
if (constructed){
get()->~T();
constructed=false;
}
if (list) list->erase(self);
}
template<class...Ts>
T* emplace(Ts&&...ts){
T* r = ::new( (void*)&data ) T(std::forward<Ts>(ts)...);
constructed = true;
return r;
}
};
template<class T, class...Args>
std::shared_ptr<T> make_and_register( weak_list<T>& list, Args&&...args ){
auto r = std::make_shared<shared_helper<T>>();
if(!r) return {};
r->emplace( std::forward<Args>(args)... );
std::shared_ptr<T> ptr( r, r->get() );
r->self = ptr;
list.insert(ptr);
r->list = &list
return ptr;
}
有点迟钝,未经测试和编译。但在这种情况下,弱列表的集合或无序集合是有意义的,因为我们使用快速查找在最后一个强引用过期时立即清理弱列表。
我的项目中有一个Factoryclass,如果调用了Create
方法,就是returnsstd::shared_ptr<MyClass>
。工厂不是所有者,但它维护一个已创建对象的列表。有时工厂需要遍历仍在使用的已创建对象,或者对它们进行计数。
我使用 std::vector<std::weak_ptr<MyClass>>
实现了这个。迭代看起来像这样:
for (std::weak_ptr<MyClass> wp : weak_list) {
if (auto sp = wp.lock()) {
//..
}
}
Create
函数:
std::shared_ptr<MyClass> Create(/* ... */) {
std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
//...
weak_list.push_back(obj);
return obj;
}
vector 是像这样的列表的最佳容器吗?也许 std::set
会更好。
如果我使用向量实现它,我必须定期检查列表中的过期指针并将其删除
在工厂中存储弱指针列表的首选方法是什么class?
默认使用矢量。
Sets不会自行清理过期指针,手动清理过程相同。
考虑在迭代之前清除死元素,并迭代弱列表的副本(以防迭代改变弱列表)。
如果您需要立即清除悬挂的弱指针,请修改共享指针以在最后一个强引用消失时从弱列表中注销自身。这需要一些与 make shared 有关的工作,包括对齐存储、手动构建和销毁、辅助结构和共享 ptr 的别名构造器。
template<class T>
struct shared_helper {
typename std::aligned_storage<sizeof(T),alignof(T)::type data;
T* get(){ return reinterpret_cast<T*>(&data); }
bool constructed = false;
weak_list<T>* list=0;
std::weak_ptr<T> self;
~shared_helper(){
if (constructed){
get()->~T();
constructed=false;
}
if (list) list->erase(self);
}
template<class...Ts>
T* emplace(Ts&&...ts){
T* r = ::new( (void*)&data ) T(std::forward<Ts>(ts)...);
constructed = true;
return r;
}
};
template<class T, class...Args>
std::shared_ptr<T> make_and_register( weak_list<T>& list, Args&&...args ){
auto r = std::make_shared<shared_helper<T>>();
if(!r) return {};
r->emplace( std::forward<Args>(args)... );
std::shared_ptr<T> ptr( r, r->get() );
r->self = ptr;
list.insert(ptr);
r->list = &list
return ptr;
}
有点迟钝,未经测试和编译。但在这种情况下,弱列表的集合或无序集合是有意义的,因为我们使用快速查找在最后一个强引用过期时立即清理弱列表。