如何优雅地使用智能指针在 C++ 中为复杂的生命周期建模?

How do I elegantly use smart pointers to model complex lifetimes in C++?

假设我有一组 Foo 个对象,每个 Foo 拥有一个或多个 Bar 个对象。我的界面的用户可以删除特定的 FooBar;当删除 Foo 时,它拥有的所有 Bar 也会被删除。到目前为止,我只需要给每个 Foounique_ptr<Bar> 的集合来自动管理这个模型。但是,我有一个额外的要求:一旦 Foo 没有任何 Bar,它也应该被删除。

当然,我可以只编写明确处理此问题的代码,但我想知道是否有更惯用的方法来实现同样的事情。这听起来很像 shared_ptr,但又不完全...

由于从 Foo 中删除所有 Bar 应该删除 Foo,这听起来确实像是您需要从 [=11] 中删除一些 shared_ptr =]s 到他们的 Foo.

但是,该模型会将 Foo 的生命周期置于其 Bar 的手中:您将无法直接删除 Foo,而是您必须找到它的所有 Bar 并删除 这些

Foo 会保留 Bar*s 而不是 unique_ptr<Bar>s,因为它不会在 Bars 之前死亡。但是你必须把 Bar 的所有权给 某人 ...

您最终可能会得到另一个对象,该对象包含与每个 Foo 对应的 unique_ptr<Bar> 的集合,但是您必须保持所有这些同步,因为 Bar来来去去。这与您试图避免的簿记类型相同,但结果更大、更复杂、更脆弱,以内存泄漏和流氓指针作为失败案例。


因此,我建议您坚持第一个 unique_ptr 驱动的想法,而不是所有这些。第一次实施可能如下所示:

struct Foo {
private:
    friend void remove(std::unique_ptr<Foo> &foo, Bar const *bar);

    // Removes the bar from this Foo.
    // Returns true iff the Foo is now empty and should be deleted.
    bool remove(Bar const *bar) {
        auto i = std::find_if(begin(_bars), end(_bars), [&](auto const &p) {
            return p.get() == bar;
        });

        assert(i != end(_bars));
        _bars.erase(i);

        return _bars.empty();
    }

    std::vector<std::unique_ptr<Bar>> _bars;
};

// Removes the bar from the Foo.
// Deletes the Foo if it becomes empty.
void remove(std::unique_ptr<Foo> &foo, Bar const *bar) {
    if(foo->remove(bar))
        foo.reset();
}

没有惯用的解决方案。在聚合内部使用 shared_ptr 和 unique_ptr,并使用 weak_ptr 作为聚合的锚点。这是我对你的问题的详尽示例:

#include <memory>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
using std::shared_ptr;
using std::unique_ptr;
using std::weak_ptr;
using std::make_shared;
using std::make_unique;

struct Foo;
struct Bar
{   int b;
    shared_ptr<Foo> f;
    Bar(int b, shared_ptr<Foo> f): b(b), f(f)  { cout << "Constructor B with: " <<b  << std::endl; }
    ~Bar() { cout << "Destructor B with: " <<b << endl; }
};
struct Foo
{
    Foo()  { cout << "Constructor Foo" << endl; }
    ~Foo() { cout << "Destructor Foo"  << endl; }
    void clear()  { vb.clear(); }
    vector<unique_ptr<Bar>> vb;
};


int main(int argc, char* argv[])
{   weak_ptr<Foo> wf;  // Anchor to Aggregate
    {   // Construction of Aggregate
        vector<shared_ptr<Bar>> vb2;
        shared_ptr<Foo> f  =std::make_shared<Foo>();
        f->vb.emplace_back(make_unique<Bar>(1, f));
        f->vb.emplace_back(make_unique<Bar>(2, f));
        wf =f;
    }
    shared_ptr<Foo> f3 =wf.lock();
    if (f3)
    {
        if (argv[1][0] =='f')
        {
            cout <<"Destroy Foo" <<endl;
            f3->clear();
        }
        if (argv[1][0] =='b')
        {
            cout <<"Destroy Bar" <<endl;
            f3->vb[0].reset();
            f3->vb[1].reset();
        }
    }
}

使用参数 'f' 或 'b' 调用程序,输出将是:

Constructor Foo
Constructor B with: 1
Constructor B with: 2
Destroy ???
Destructor B with: 1
Destructor B with: 2
Destructor Foo