Reputation: 4294
I want to implement the Mediator
design pattern using shared_ptr
for all the program.
Here is the Mediator interface
:
class Mediator
{
public:
Mediator(){ print("Mediator()"); }
virtual void Notify(std::shared_ptr<BaseComponent> sender) const = 0;
};
Here is the ExampleMediator
:
class ExampleMediator : public Mediator
{
private:
std::shared_ptr<ExampleComponent> eC;
public:
void Notify(std::shared_ptr<BaseComponent> sender) const override {
print("From Example Mediator");
}
void setExampleComponent(std::shared_ptr<ExampleComponent> eC_){
eC = eC_;
}
};
The ExampleMediator
has a shared pointer to ExampleComponent
and a method to set it.
This is the base class BaseComponent
:
class BaseComponent
{
protected:
std::shared_ptr<Mediator> m;
public:
BaseComponent() { print("BaseComponent()"); }
~BaseComponent() { print("~BaseComponent()"); }
void setMediator(std::shared_ptr<Mediator> m_){ m = m_; }
};
The BaseComponent
has a shared pointer to the ExampleMediator
and a method to set it.
Here is the ExampleComponent
:
class ExampleComponent: public BaseComponent
{
public:
ExampleComponent(){ print("ExampleComponent()"); }
~ExampleComponent(){ print("~ExampleComponent()"); }
void doSomethingOnDerived(){ print("ExampleComponent job");}
};
The main function:
int main()
{
// Create the mediator
auto mM = std::make_shared<ExampleMediator>();
// Create the component
auto eC = std::make_shared<ExampleComponent>();
eC->setMediator(mM);
// Set the component in the mediator
mM->setExampleComponent(eC);
}
The output is:
Mediator()
BaseComponent()
ExampleComponent()
If I remove the line mM->setExampleComponent(eC);
the constructors get called.
Live code in Compiler Explorer: https://godbolt.org/z/E5ofEPGen
My goal is to use the components as shared pointers and not raw pointers, same for the Mediator.
What can be the cause for this issue?
Thanks.
Upvotes: 0
Views: 414
Reputation: 238311
What can be the cause for this issue?
Shared pointers destroy their owned resource when the pointer is the last owner pointing to the resource. When local variable eC
is destroyed on return of main
, there is still another owner mM.eC
so the resource won't be destroyed. Similarly, when the local mM
is destroyed, its resource is still owned by the resource previously owned by eC
.
When you own a resource, we typically consider the owner to "depend" on the resource. If we consider objects as nodes and dependency relations as edges, we get a directed graph. This dependency graph should not have loops, because that typically leads to the problem that you encountered.
With shared pointers, one way to break the loop is to weaken the ownership of one node. This can be done by using a weak pointer instead of a shared pointer. Note that you must then take care to handle the case where weakly owned resource has been destroyed before its dependee.
Upvotes: 2