如何安全地填充 Boosts 的指针容器?

How to safely fill Boosts's pointer containers?

Boost Pointer Container 的第一个示例将原始指针添加到结构:

class zoo
{
    boost::ptr_vector<animal> the_animals;
public:

    void add_animal( animal* a )
    {
        the_animals.push_back( a );
    }
};

但是,如果 push_back 或任何其他可能触发重新分配的成员函数在此过程中抛出异常怎么办?根据我的理解,在那种情况下,由调用者来管理给定对象的内存,但是因为调用者将原始指针传递给 class ,其目的是管理内存,所以很可能来电者没有。

那么,在将指针提供给容器之前,是否需要在上面的代码示例中使用某种独特的智能指针来包装指针,并绝对确保没有内存泄漏?容器确实为此类智能指针提供了重载,但它们不强制使用它们。

或者说容器在任何添加操作期间都不会抛出异常并且总是成功的论点?

如果您使用的是 std::vector<animal*> 而不是 boost::ptr_vector<animal>,那么您的担忧就非常有道理。 Boost.PointerContainer 旨在处理指向需要释放的资源的指针,因此它使您不必担心这些事情。

Boost 文档为各种成员函数提供异常安全保证。 ptr_vectorptr_sequence_adaptor 继承了 push_back,并且将 push_back 的行为列为

void push_back( T* x );

Requirements: x != 0
Effects: Inserts the pointer into container and takes ownership of it
Throws: bad_pointer if x == 0
Exception safety: Strong guarantee

strong guarantee 意味着如果 push_back 抛出,容器的状态将回滚到调用 push_back 之前的状态,并且不会泄漏任何资源。现在,您可能会争辩说,这并不能保证您尝试添加到容器中的资源的任何内容,但是对于实现而言,允许该资源泄漏将是非常糟糕的形式,特别是因为调用 push_back 应该取得调用者传递的对象的所有权。

如果我们查看 push_backimplementation,它会显示 ptr_vector 如何保证您尝试添加的资源不会泄露。

void push_back(value_type x)  // strong               
{
    this->enforce_null_policy(x, "Null pointer in 'push_back()'");

    auto_type ptr(x);           // notrow
    this->base().push_back(x);  // strong, commit
    ptr.release();                // nothrow
}

因此,在尝试实际的 push_back 操作之前首先构建 auto_type。进一步挖掘发现 auto_typestatic_move_ptr 的别名,它是一种智能指针类型,必要时会在销毁时释放它拥有的资源。

因此,在所示示例中,您尝试添加的 animal * 永远不会被泄露,即使抛出异常也是如此。