In designing an observer pattern for my code, I encountered the following task: I have a class Foo which contains a variable std::shared_ptr<Bar> and I want to use a weak_ptr<Bar> to this shared-pointer to safely call a function update() in Foo.
Here is an example code:
struct Bar
{
void call_update_in_foo() { /* how to implement this function? */}
};
struct Foo
{
virtual void update() = 0;
std::shared_ptr<Bar> bar;
};
As mentioned there is a weak_ptr<Bar> from which I want to call Foo::update() -- at most once -- via Bar::call_update_in_foo():
Foo foo;
std::weak_ptr<Bar> w (foo.bar);
auto s = w.lock();
if(s)
{
s->call_update_in_foo(); //this shall call at most once Foo::update()
//regardless how many copies of foo there are.
}
(fyi: the call of update() should happen at most once because it updates a shared_ptr in some derived class. However imo it doesn't affect the question about "safeness".)
- What is an appropriate implementation of
FooandBarto carry out that process in a safe manner?
Here is an attempt for a minimal implementation -- the idea is that Bar manages a set of currently valid Foo objects, of which one member is called:
struct Bar
{
std::set<Foo *> foos;
void call_update_in_foo() const
{
for(auto& f : foos)
{
f->update();
break; //one call is sufficient
}
}
};
The class Foo has to take care that the std::shared_ptr<Bar> object is up-to-date:
struct Foo
{
Foo()
{
bar->foos.insert(this);
}
Foo(Foo const& other) : bar(other.bar)
{
bar->foos.insert(this);
}
Foo& operator=(Foo rhs)
{
std::swap(*this, rhs);
return *this;
}
~Foo()
{
bar->foos.erase(this);
}
virtual void update() = 0;
std::shared_ptr<Bar> bar = std::make_shared<Bar>();
};
-
Is this already safe? -- "safe" meaning that no expired
Fooobject is called. Or are there some pitfalls which have to be considered? -
If this code is safe, how would one implement the move constructor and assignment?
(I know this has the feeling of being appropriate for CodeReview, but it's rather about a reasonable pattern for this task than about my code, so I posted it here ... and further the move constructors are still missing.)
Aucun commentaire:
Enregistrer un commentaire