Should safe pointers be used in a strategy template?

Given a typical strategy template

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 that the pre-C ++ 11 method for implementing the context class would be similar to

 class ContextRaw { public: ContextRaw(Strategy* the_strategy); ~ContextRaw(); // Should this delete the_strategy_? int execute() const; private: Strategy* the_strategy_; } 

For me in this design it is not clear whether Context take responsibility for the Strategy , and if it does not have clear documentation indicating otherwise, bad things can happen if they are

 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 the light of safe pointers, should it now be preferable to introduce a safe pointer and have Context take charge of 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 divided between 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 its own, in particular, only dynamically allocated Strategy can be entered into Context .

+2
source share
3 answers

You are doing it wrong.

In the light of std::function , everything you just wrote is completely outdated, and you should just use std::function<int()> and some lambdas.

+3
source

Design up to the developer.

Note that in your examples, you refer to different ways of imposing a strategy template using pointers other than C ++ 11.

To answer your question directly:

Yes, you should use smart pointers in your strategy template.

To answer the question:

You should use smart pointers whenever possible.

The reason is that smart pointers almost independently document from the point of view of memory ownership policy, so you get rid of some of the shortcomings of “If there is no good documentation”.

Given the prototype that you expose for your Context class, you can tell users what your expectations are:

  • unique_ptr if you expect the user to transfer ownership of memory to you
  • shared_ptr, if you expect the same strategy implementation to be used for multiple owners
  • weak_ptr if you want the user to handle memory management

Which is safer is up to you. However, you can tell users that a Context can share it with a specific Context, or that there is 1 Specific Strategy for a Context.

As a constructive approach, I would suggest switching from 1 Strategy / Context (so unique_ptr), since your specific strategies may cause some internal variables to be unique / contexts, and from this moment the situation becomes more complicated.

+2
source

This greatly depends on what the real purpose of the Strategy is, whether they should be divided between different context objects or belonging to them.

At least when you use generic or unique ptr, you clearly define your intentions. You should use the "raw" pointer only if you are going to "browse" some other objects (you do not share or own it), and you are sure that the pointing object will not survive the pointed one).

0
source

Source: https://habr.com/ru/post/983743/


All Articles