c++ - 使用 unique_ptr 指示(非)所有权转移

标签 c++ c++11 unique-ptr

假设我有这样一个类:

class Node {
public:
    Node(Node* parent = 0) : mParent(parent) {}
    virtual ~Node() {
        for(auto p : mChildren) delete p;
    }

    // Takes ownership
    void addChild(Node* n);

    // Returns object with ownership
    Node* firstChild() const;

    // Does not take ownership
    void setParent(Node* n) { mParent = n; }

    // Returns parent, does not transfer ownership
    Node* parent() const { return mParent; }

private:
list<Node*> mChildren;
Node* mParent;
};

我现在想使用智能指针和/或右值引用来指示所有权转移和未转移的位置。

我的第一个猜测是更改 mChildren 以包含 unique_ptr,按如下方式调整函数签名。

    // Takes ownership
    void addChild(unique_ptr<Node> n);

    // Returns object with ownership
    unique_ptr<Node>& firstChild() const;

    // Does not take ownership
    void setParent(Node* n) { mParent = n; }

    // Returns parent, does not transfer ownership
    Node* parent() const { return mParent; }

现在,当我需要将 Node::firstChild() 的结果传递给某个观察它但不取得所有权的函数时,这会有点问题,因为我需要在 unique_ptr 上显式调用 .get(),据我所知,不推荐这样做。

使用 unique_ptr 指示所有权的正确和推荐方法是什么,而不必求助于使用 .get() 并传递裸指针?

最佳答案

起初,我会使用 std::vector而不是 std::list包含 child 。除非你有强烈的动机使用它,std::vector应该是默认容器。如果您担心性能,请不要担心,因为std::vector 完成了连续分配。可能会导致更高的缓存命中率,从而极大地加快对 std::list 的访问速度,这意味着分散的分配/访问模式。

其次,您的 std::vector<std::unique_ptr<Node>> 是正确的用于持有子节点,因为假设一个节点持有其子节点的所有权是合理的。除 addChild() 接受的指针外的所有其他指针,另一方面,应该是非拥有原始指针。

这适用于 mParent指针和 Node 返回的指针的成员函数。事实上,firstChild()成员函数甚至可以返回一个引用,如果节点没有子节点则抛出异常。这样您就不会混淆谁拥有返回的对象。

返回 unique_ptr ,或对 unique_ptr 的引用, 不是正确的用法:唯一指针代表所有权,而您不想将所有权授予 Node 的客户.

这就是您的类(class)的样子:

#include <vector>
#include <memory>
#include <stdexcept>

class Node {
public:
    Node() : mParent(nullptr) { }

    void addChild(std::unique_ptr<Node>&& ptr) {
        mChildren.push_back(std::move(ptr));
        ptr->setParent(this);
    }

    Node& firstChild() const {
        if (mChildren.size() == 0) { throw std::logic_error("No children"); }
        else return *(mChildren[0].get());
    }

    Node& parent() const {
        if (mParent == nullptr) { throw std::logic_error("No parent"); }
        else return *mParent;
    }

private:

    void setParent(Node* n) { 
        mParent = n; 
    }

    std::vector<std::unique_ptr<Node>> mChildren;
    Node* mParent;
};

如果您想避免抛出异常,您当然可以决定返回非拥有的、可能为空的原始指针而不是引用。或者您可以添加一对 hasParent()getNumOfChildren()检索有关 Node 信息的方法的状态。这将允许客户端在不想处理异常时执行检查。

关于c++ - 使用 unique_ptr 指示(非)所有权转移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16373212/

相关文章:

c++ - 一次只能操纵一个 union 成员是什么意思?

c++ - std::get 使用枚举类作为模板参数

c++ - unique_ptr 的 lambda 删除器导致编译错误与仿函数

c++ - 如何将 unique_ptr.get() 的引用传递给函数

c++ - "Downcasting"unique_ptr<Base> 到 unique_ptr<Derived>

c++ - 什么是正确的 std::set_union 代码?

c++ - 什么会导致 HP-UX 和 LINUX for C++ 应用程序的返回值不同?

c++ - 非 MFC ATL 项目 (dll) 产生 MFC 相关错误

c++ - 我如何在 C++11 中实现类似 "interrupted exception"行为的 Java

c++ - c++11对于三种方法的规则如何实现 "... = default;"