【问题标题】:Release resource on boost::shared_ptr finalization在 boost::shared_ptr 完成时释放资源
【发布时间】:2010-09-17 17:17:51
【问题描述】:

我确实从库调用中收到了一个 shared_ptr,并将它和一些资源传递回库中。资源只有在 shared_ptr 删除其指针时才能被删除:

std::ofstream* out = new std::ofstream(); 
...
shared_ptr<Lib::SomeClass> writer = Library.createWriter(out);

Library.appendWriter(writer);

图书馆希望我能做到*,但不告诉我什么时候这样做是安全的。本质上,如果writer 被释放,我希望out 被删除。

这可以使用 boost 的删除工具来实现吗?想法?

【问题讨论】:

  • 在我看来,createWriter() API 定义的合约应该指定谁拥有stream* 的输入,并暗示它如何以及何时发布。图书馆要么发布它,要么你必须发布它。我认为将其封装在 shared_ptr 中没有帮助,除非 createWriter() 是这样定义的。
  • 他们没有指定它,但是从他们的代码中我看到他们希望我拥有它。不幸的是,当他们不再使用它时,他们没有告诉我。这就是为什么它认为等待 shared_ptr 被释放可能是一个可行的解决方案。
  • 除非 API 接受 shared_ptr,否则您将回到原点。将 ofstream 交给图书馆后会发生什么?当不再使用时,它在库代码中是否明显?如果您可以将最终 ofstream 的使用与代码中的 API 使用相关联,则可以确定一个合理的点,假设您可以清理流。
  • 附带说明:如果您使用的 Library 位于单独的模块 (.dll/.so) 中,那么您的 shared_ptr 删除器应该是匹配的库调用(Library.releaseWriter(writer) 或类似的),跨模块边界进行新建/删除是一件非常棘手的事情。
  • 谢谢大家!所以我必须与库设计者协商更改他们的接口(没有 releaseWriter 或回调)。我真的会认为 boost 有一种方法可以通知 shared_ptr 被释放。

标签: c++ boost shared-ptr


【解决方案1】:

我不相信您可以直接使用 shared_ptr API 执行此操作。

如果 Lib::SomeClass 是接口/抽象基类,您也许可以使用 Decorator。想法是定义一个类,它是Lib::SomeClass 的子类,包含shared_ptr&lt;Lib::SomeClass&gt;std::ofstream*,其方法都转发到包含的shared_ptr 的相应方法。然而,装饰器的析构函数会删除包含的ofstream(或者您可以将其存储在某种RAII 容器中,例如scoped_ptr)。所以它将是您传递给 appendWriter 的装饰器的一个实例。这是一个草图:

class SomeClassDecorator : public Lib::SomeClass
{
  public:
    SomeClassDecorator(shared_ptr<Lib::SomeClass> p, std::ofstream* stream)
      : p_(p), stream_(stream)
    {}

    virtual int MethodOfSomeClass(int x) {
        return p_->MethodOfSomeClass(x);
    }

  private:
    shared_ptr<Lib::SomeClass> p_;
    scoped_ptr<std::ofstream> stream_;
};

std::ofstream* out = new std::ofstream(); 
...
shared_ptr<Lib::SomeClass> writer = Library.createWriter(out);
shared_ptr<Lib::SomeClass> wrapper(new SomeClassDecorator(writer, out));

Library.appendWriter(wrapper);

【讨论】:

  • 谢谢! writer 确实是一个接口,所以这种方法效果很好!
【解决方案2】:

您可以尝试在堆栈上创建输出流,该范围内的寿命保证比任何对writer 的引用都要长。这取决于您的架构,这是否可能(尽管我认为在一个好的架构中应该是这样)。

如果您有机会与图书馆设计师进行谈判(正如您在评论中提到的那样),请告诉他/她将论据作为参考,如果这足够了。 shared_ptr 只有在对象的所有权真正共享时才应该使用。

【讨论】:

  • 很遗憾,这里的 API 设计是歪的。堆栈的寿命不够长,无法看到正在使用的编写器的结尾。
  • @Christopher Oezbek:嗯,一些堆栈帧必须至少与最后一个指针一样长。但我承认,将输出流放在不属于这个的地方可能会更糟糕。
猜你喜欢
  • 1970-01-01
  • 2015-03-29
  • 2017-10-22
  • 2010-12-04
  • 1970-01-01
  • 2014-09-12
  • 2011-06-23
  • 1970-01-01
  • 2012-01-08
相关资源
最近更新 更多