问题
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.
回答1:
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.
回答2:
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 :
- unique_ptr if you expect the user to pass memory ownership to you
- shared_ptr if you expect the same strategy implementation to be used on multiple owners
- weak_ptr if you want the user to handle memory management
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.
回答3:
It strongly depends on what's the real purpose of Strategy objects whether they should be shared between various Context objects or owned by them.
At least when you use the shared or unique ptr, you clearly define your intentions. You should use a "raw" pointer only if you are going to "view" some other objects (you don't share nor own it - and you are sure that the pointing object won't outlive the pointed one).
来源:https://stackoverflow.com/questions/28364689/should-safe-pointers-be-used-in-strategy-pattern