我应该如何构建一个旨在用std :: shared_ptr管理的实例?

时间:2014-04-07 12:40:15

标签: c++11 shared-ptr

考虑以下父/子对象模型。目的是让父母和孩子都使用shared_ptr来管理他们的一生。父母应该保留shared_ptr来保留其子女,孩子将保留weak_ptr给父母。

鉴于这些对象的目的是始终由std::shared_ptr管理,构建它们的最佳方法是什么?我提出的方法(到目前为止)感觉有点笨重:我使用工厂(朋友)函数和私有构造函数来降低指向这些对象的原始指针" escape&#的可能性34 ;.然后,孩子在ctor中创建一个shared_ptr this,并将其放入父母的vector个孩子中。当ctor将原始指针返回到工厂函数时,工厂函数使用shared_from_this()得到一个shared_ptr,它被连接到" (即与父母的孩子矢量中的shared_ptr共享参考计数)。

这是我到目前为止所提出的:

class Child; // Forward decl

class Parent : std::enable_shared_from_this<Parent> {
public:                
    int value() const { return _value; };
    void set_value(int newValue) { _value = newValue; };

    std::vector<std::shared_ptr<const Child>> children() const {
        // propagate const-ness to the child pointers we hand back.
        return std::vector<std::shared_ptr<const Child>>(begin(_children), end(_children));
    };

    std::vector<std::shared_ptr<Child>> children() {
        return _children;
    };

private:

    Parent(int value) : _value(value) {};

    friend class Child; // So it can add itself to the _children vector
    friend class std::shared_ptr<Parent>; // So that I don't have to inherit public from enable_shared_from_this
    friend std::shared_ptr<Parent> CreateParent(int value); // So it can call the private ctor

    std::vector<std::shared_ptr<Child>> _children;
    int _value;
};

class Child : std::enable_shared_from_this<Child>
{
public:
    int value() const { return _value; };
    void set_value(int newValue) { _value = newValue; };

private:
    Child(const std::shared_ptr<Parent>& parent, int value) : _parent(parent), _value(value) {
        std::shared_ptr<Child> sp(this); // This feels wrong, but the existence of the shared_ptr in the parent's vector of children ensures that the precondition for calling shared_from_this() is met
        parent->_children.push_back(sp);
    };

    friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value); // So it cal call the private ctor
    friend class std::shared_ptr<Child>; // So that I don't have to inherit public from enable_shared_from_this

    std::weak_ptr<Parent> _parent;
    int _value;
};

std::shared_ptr<Parent> CreateParent(int value) {
    return std::shared_ptr<Parent>(new Parent(value));
};

std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value) {
    std::shared_ptr<Child> rv = (new Child(parent, value))->shared_from_this();
    return rv;
};

这似乎有效,但男人,感觉笨重。还有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

我这样做:

class Child;

class Parent {
public:
    std::vector<const Child*> children() const {
        // propagate const-ness to the child pointers we hand back.
        // ...
    }

    const std::vector<std::unique_ptr<Child>>& children() {
        return _children;
    }

    std::shared_ptr<Parent> create() {
        // I'd rather use std::make_shared() here but it needs public ctor
        return std::shared_ptr<Parent>(new Parent());
    }

    std::unique_ptr<Child>& createChild() {
        _children.emplace_back(new Child(this));
        return _children.back();
    }

private:    
    Parent();

    std::vector<std::unique_ptr<Child>> _children;
};

class Child
{
private:
    Child(Parent* parent) : _parent(parent) {}

    friend class Parent;

    Parent* _parent;
};

我删除了&#34;值&#34;样板清晰。我还尝试使用最低级别的智能指针来完成工作。我可能没有100%完美地针对您的特定用例,但您应该考虑更明确定义的生命周期/所有权语义。让一切都分享一切都是一团糟,导致缺乏清晰度......拥有明确的所有权可以使事情变得更简单。由于Parent类仍然管理每个Child的生命周期,因此不需要从Child返回Parent的花哨指针 - 原始指针将起作用,因为Child不会比Parent更长。 / p>

答案 1 :(得分:1)

鉴于您对父/子管理的不舒服分裂的描述,您可以简化如下,

class Child;

class Parent {
private:
    Parent() {};
    friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
    std::vector<std::shared_ptr<Child>> _children;
};

class Child {
private:
    Child(const std::shared_ptr<Parent>& parent) : _parent(parent) {};
    friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
    std::weak_ptr<Parent> _parent;
};

std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent) {
    auto child = std::shared_ptr<Child>(new Child(parent));
    parent->_children.push_back(child);
    return child;
}

另请注意,此处没有shared_from_this,也许您的其他目的是必要的,但管理父子关系并不是必需的。