Given a typical strategy pattern
class Strategy
{
public:
virtual int execute() const = 0;
}
class StrategyA : public Strategy
{
public:
int execute() const override;
}
class StrategyB : public Strategy
{
public:
int execute() const override;
}
I believe the 'pre-C++11' way to implement a context class would be something like
class ContextRaw
{
public:
ContextRaw(Strategy* the_strategy);
~ContextRaw(); // Should this delete the_strategy_?
int execute() const;
private:
Strategy* the_strategy_;
}
To me, in this design it's not clear if Context
should take responsibility for Strategy
, and unless there is clear documentation stating otherwise, bad things might happen if it does
void trouble()
{
StrategyA a_concrete_strategy;
ContextRaw a_context(&a_concrete_strategy); // Oops, Context may try to delete stack variable
}
void more_trouble()
{
Strategy* a_concrete_strategy = new StrategyA;
ContextRaw* a_context = new ContextRaw(a_concrete_strategy);
ContextRaw* another_context = new ContextRaw(a_concrete_strategy);
delete a_context;
std::cout << another_context.execute() << std::endl; // Oops, the_strategy is deleted
}
In light of safe-pointers, should it now be preferable to inject a safe pointer, and have Context
take ownership of the Strategy
?
class ContextUnique
{
public:
ContextUnique() = delete;
ContextUnique(std::unique_ptr<Strategy> the_strategy);
~ContextUnique();
int execute() const;
private:
std::unique_ptr<Strategy> the_strategy_;
}
or if Strategy
can be shared amongst different Context
?
class ContextShared
{
public:
ContextShared() = delete;
ContextShared(std::shared_ptr<Strategy> the_strategy);
~ContextShared();
int execute() const;
private:
std::shared_ptr<Strategy> the_strategy_;
}
This design of course introduces problems of it's own, in particular only dynamically allocated Strategy
's can be injected into Context
.
The design is up to the implementator.
Notice that in your examples you reference different ways of screwing up with Strategy pattern using non C++11 pointers.
To answer directly to your question :
Yes you should use smart pointers in strategy pattern.
To further answer the question :
You should use smart pointers whenever possible.
The reason is that smart pointers practically are self documenting in terms of memory ownership policy, so you get rid of some the drawbacks of "If no good documentation".
Considering the prototype that you expose for your Context class , you can tell users what are your expectations :
What is safer, it's up to you. However , you are able to tell users that the Context can share it's concrete strategy with other Contexts OR that there is 1 Concrete strategy per Context.
As a design approach, I would suggest to go with 1 Strategy / Context (so unique_ptr) since your concrete strategies might end up having some internal variables that are unique / context , and things will get complicated from there on.
You're doing it wrong.
In the light of std::function
, everything you've just written is completely obsolete and you should just use std::function<int()>
and some lambdas.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With