我有一个将weak_ptrs存储在容器中的类,如果weak_ptr没有过期,我会做一些事情:
class Example
{
public:
void fill(std::shared_ptr<int> thing)
{
member.push_back(thing);
}
void dosomething() const
{
for (const auto& i : member)
if (!i.expired())
;// do something. the weak_ptr will not be locked
}
private:
std::vector<std::weak_ptr<int>> member;
};
如果Example
是一个永远存在且永久使用fill
的对象,则该向量会连续为元素分配内存,但它们在过期后永远不会被删除。
是否有任何自动C ++方法可以摆脱容器中过期的weak_ptrs,或者有更好的方法来存储可变数量的它们吗?
我天真的方式是每次调用fill
时迭代容器并删除所有过期的weak_ptrs。在Example
容器中有许多元素并且频繁调用填充的情况下,这似乎效率很低。
答案 0 :(得分:5)
由于您澄清说您实际上使用的是std::map
而不是std::vector
,因此在doSomething()
中即时删除已过期的元素可能最为简单。从基于范围的for循环切换回基于正常迭代器的设计:
void dosomething() const
{
auto i = member.begin();
while( i != member.end() ) {
if( i->expired() ) { i = member.erase( i ); continue; }
;// do something. the weak_ptr will not be locked
++i;
}
}
答案 1 :(得分:2)
我宁愿为shared_ptr使用自定义删除器。但这意味着要更改Example类的接口。使用自定义删除器的优点是无需检查集合中的过期对象。该集合由自定义删除程序直接维护。
快速实施:
#include <memory>
#include <iostream>
#include <set>
template <typename Container>
// requires Container to be an associative container type with key type
// a raw pointer type
class Deleter {
Container* c;
public:
Deleter(Container& c) : c(&c) {}
using key_type = typename Container::key_type;
void operator()(key_type ptr) {
c->erase(ptr);
delete ptr;
}
};
class Example {
public:
// cannot change the custom deleter of an existing shared_ptr
// so i changed the interface here to take a unique_ptr instead
std::shared_ptr<int> fill(std::unique_ptr<int> thing) {
std::shared_ptr<int> managed_thing(thing.release(), Deleter<containter_type>(member));
member.insert(managed_thing.get());
return managed_thing;
}
void dosomething() const {
// we don't need to check for expired pointers
for (const auto & i : member)
std::cout << *i << ", ";
std::cout << std::endl;
}
using containter_type = std::set<int*>;
private:
containter_type member;
};
int main()
{
Example example;
auto one = example.fill(std::unique_ptr<int>(new int(1)));
auto two = example.fill(std::unique_ptr<int>(new int(2)));
auto three = example.fill(std::unique_ptr<int>(new int(3)));
example.dosomething();
three.reset();
example.dosomething();
}
答案 2 :(得分:1)
shared_ptr<int>
必须是shared_ptr<int>
吗?
shared_ptr<IntWrapper>
怎么样?
#include <iostream>
#include <forward_list>
using namespace std;
class IntWrapper {
public:
int i;
static forward_list<IntWrapper*>& all() {
static forward_list<IntWrapper*> intWrappers;
return intWrappers;
}
IntWrapper(int i) : i(i) {
all().push_front(this);
}
~IntWrapper() {
all().remove(this);
}
};
void DoSomething() {
for(auto iw : IntWrapper::all()) {
cout << iw->i << endl;
}
}
int main(int argc, char *argv[]) {
shared_ptr<IntWrapper> a = make_shared<IntWrapper>(1);
shared_ptr<IntWrapper> b = make_shared<IntWrapper>(2);
shared_ptr<IntWrapper> c = make_shared<IntWrapper>(3);
DoSomething();
return 0;
}