在操作之前或之后清理/重置

时间:2014-01-20 20:58:33

标签: c++ poco

情况就是这样:

我想使用一类第三方库(即Poco)来解析JSON字符串。这个Parser类的设计方式是每次解析(操作)后都必须重新设置(通过调用reset(),谁会想到它?)。我在我正在实现的类中的不同位置多次重用一个Parser,因此这对我很重要。即使班级已经重置,调用reset()也是无害的。

因此我的问题是:我是否应该确保在每次操作之前重置解析器,或者我应该确保在操作后重置它。

第一种情况很方便,因为它确保我的解析器在操作之前处于正确的状态,但同时我感觉很脏,因为我让解析器处于无效状态,而其他人可能希望我重置解析器。

我不喜欢第二种情况,因为我担心我可能会错过我的方法可能退出的情况(例如未捕获的异常),使解析器处于无效状态,而其他人则期望它确实有效。当然这可以通过使用RAII(就像一个范围锁)来解决,但这对我来说听起来有点过时了。

另一种解决方案可能是结合两种情况,所以:重置,解析和重置;但这是一种多余的IMO。


我真的不确定这里并且不能决定任何这些情况,我希望你的意见(基于与设计相关的考虑因素,你不关闭我的问题!;))将帮助我选择。

3 个答案:

答案 0 :(得分:3)

好吧,我建议不要使用Poco,而是看JsonCpp。 通过让你调用重置来制作Poco的设计选择相当奇怪。 除此之外,RAII方法相当简单:

template <typename T>
struct ScopedParser {
    T& parser; // parser object

    ScopedParser(T& p) : parser(p) {} // set parser in constuctor
    ScopedParser(ScopedParser&&) = delete; // no moving
    ScopedParser(const ScopedParser&) = delete; // no copying

    ~ScopedParser() {
        parser.reset(); // reset it
    }
}

如何使用它的示例:

void myFunc() {
    Poco::JSONParser p;
    ScopedParser<Poco::JSONParser> pScoped(p);
}

答案 1 :(得分:1)

这似乎是将解析器嵌入RIIA样式类的合适案例。 我们的目标是创造一个独特的用户&#34;你的解析器。

这是一个快速模拟:

class MyParserBuilder
{
public:

  class MyParser
  {
  public:
    MyParser(poco::Parser& parser, MyParserBuilder& builder) : 
    _parser(parser), 
    _builder(builder)
    {

    }

    ~MyParser() 
    { 
      _builder.reset(); 
    }

   // Either expose some functions from the parser or use 
   // something like:
    poco::Parser& operator*() { return _parser; }

  private:
    poco::Parser& _parser;
    MyParserBuilder& _builder;
  };

  MyParserBuilder() : _used{false} {}

  std::unique_ptr<MyParser> build() 
  { 
      if (_used) // Or lock ?
      {
        return std::unique_ptr<MyParser>();
      }
      _used = true;
      return std::unique_ptr<MyParser>(new MyParser(_parser, *this)); 
    }

    void reset()
    {
      _parser.reset();
      _used = false;
    }

  private:
    bool _used; 
    poco::Parser _parser;
};

http://ideone.com/6wwg20

为了安全起见,我还要补充一些类似于&#34;脏&#34;状态,以便您只能执行每次MyParser实例化时需要重置一次的操作。

答案 2 :(得分:1)

第一种情况听起来不错,只要“其他”只是在同一个私有Parser对象上运行的其他成员函数。

结合两种情况只会减少潜在的错误。可能仍然存在未捕获的异常,而其他人可能期望解析器被重置。

最佳选择仍然是RAII锁定式帮助对象。我不认为类似5行的类是过度工程。如果解析器被多个线程使用,你可以在那里添加一个真正的锁。

或者甚至为每个函数都有一个新的作用域Parser,如果它对你的应用程序的性能不是一个问题。这甚至可能比同步对同一解析器的访问更快。