2015-02-06 63 views
2

给定一个典型的战略格局应该在策略模式中使用安全指针吗?

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; 
} 

我相信“前C++ 11”的方式来实现一个上下文类会是这样的

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

对我来说,在这样的设计是不是如果Context应该对Strategy承担责任,并且除非有明确的文件另有说明,否则可能会发生不好的事情

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 
} 

鉴于安全指针,现在应该注入一个安全指针,并让Context获得Strategy的所有权?

class ContextUnique 
{ 
public: 
    ContextUnique() = delete; 
    ContextUnique(std::unique_ptr<Strategy> the_strategy); 
    ~ContextUnique(); 
    int execute() const; 
private: 
    std::unique_ptr<Strategy> the_strategy_; 
} 

或者如果Strategy可以在不同的Context之间共享?

class ContextShared 
{ 
public: 
    ContextShared() = delete; 
    ContextShared(std::shared_ptr<Strategy> the_strategy); 
    ~ContextShared(); 
    int execute() const; 
private: 
    std::shared_ptr<Strategy> the_strategy_; 
} 

当然这样的设计引入了它自己的问题,特别是只有动态分配Strategy的可注入Context

+1

为什么'Context'不能通过* reference *获取'Strategy'?那么,没有歧义! – Nim 2015-02-06 11:31:38

回答

3

你做错了。

根据std::function,您刚刚编写的所有内容都已完全过时,您应该只使用std::function<int()>和一些lambda表达式。

+0

你不需要使用带'std :: function'的lambda表达式,它只允许你这样做。当然它也避免了混淆所有权语义。 – Lionel 2015-02-06 13:11:21

+0

尽管我很欣赏你的输入,但如果你能解释为什么使用'std :: function'是一个更好的方法,而不是只是在强调我的问题,那将是很好的。 – Daniel 2015-02-06 13:47:53

+0

@Daniel使用'std :: function'将避免所有权问题,因为您不再需要通过指向base的参数传递参数。只要允许'std :: function'包装你的函数,它将代表你处理内存管理。 – Lionel 2015-02-06 14:12:24

0

它强烈依赖于Strategy对象的真正目的是什么,它们是应该在各种Context对象之间共享还是由它们拥有。

至少当你使用共享或唯一的ptr时,你明确地定义了你的意图。只有当您要“查看”其他一些对象时,才应该使用“原始”指针(您不共享也不拥有它 - 并且您确定指针对象不会超出指向的对象)。

2

设计由实施者决定。

请注意,在您的示例中,您将引用使用非C++ 11指针与Strategy模式搞砸的不同方式。

直接回答你的问题:

是的,你应该在战略模式中使用智能指针。

要进一步回答问题:

您应该尽可能使用智能指针。

原因是智能指针在内存所有权策略方面实际上是自我记录,因此您可以摆脱一些“如果没有好文档”的缺点。

考虑到你揭露你的Context类的原型,你可以告诉你有什么期望用户:

  • 的unique_ptr如果你希望用户通过内存所有权转让给你
  • shared_ptr的,如果你希望的同样的策略实现同时对多个业主使用
  • weak_ptr的,如果你希望用户来处理内存管理

什么是安全的,它是由 给你。但是,您可以告诉用户Context可以与其他上下文共享其具体策略,或者每个Context有1个具体策略。作为一种设计方法,我会建议使用1策略/上下文(如unique_ptr),因为你的具体策略可能最终会有一些内部变量是唯一的/上下文的,事情会变得复杂。