如何操作包含`unique_ptr`的类的实例?

时间:2017-05-21 21:24:24

标签: c++ pointers unique-ptr

我有一个看起来像这样的结构:

struct TreeNode
{
    int value;
    std::unique_ptr<TreeNode> left = nullptr, right = nullptr;
};

我想最好使用unique_ptr而不是shared_ptr来实现这样的树实现,对吗?

然后我在priority_queue中添加了几个节点,例如:

bool operator<(const TreeNode& t1, const TreeNode& t2)
{
    return t1.value < t2.value;
}

...

std::priority_queue<TreeNode> nodes;

for(int i = 0; i < 10; i++)
{
    TreeNode node;
    node.value = i;
    nodes.push(node);
}

之后,unique_ptr遇到问题时,我必须做这样的事情:

TreeNode n1 = nodes.top();
nodes.pop();
TreeNode n2 = nodes.top();
nodes.pop();

TreeNode node;
node.value = n1.value * n2.value;
node.left = std::unique_ptr<TreeNode>(new TreeNode(n1));
node.right = std::unique_ptr<TreeNode>(new TreeNode(n2));

这段代码显然不起作用,但我想知道如何让它尽可能简单地工作。

我设法用我从互联网上获得的make_unique实现做了一些事情,但它过于临时。我也尝试使用std::movestd::forward,但没有成功。

此外,我必须稍后做这样的事情:

std::unique_ptr<TreeNode> root(new HuffmanTreeNode(my_root));

std::unique_ptr<TreeNode> current_node = node;

while(current_node)
{
    current_node = current_node->left;
}

在这里,它显然不起作用,但我不知道如何使其正常工作。 (算法也是无稽之谈,只是为了解释我的问题)

你能给我一个例子,告诉我如何在这里完成吗?也许有某种方法可以将unique_ptr转换为shared_ptr然后进行反向操作?

1 个答案:

答案 0 :(得分:2)

TreeNode没有复制构造函数(因为隐式构造函数不正确,因为leftright不可复制)但它确实有一个隐式移动构造函数,它会将leftright移动到新对象中。您有几个地方可以尝试复制:

std::priority_queue<TreeNode> nodes;

for(int i = 0; i < 10; i++)
{
    TreeNode node;
    node.value = i;
    nodes.push(node); // Attempts copy of node
}

// ...

TreeNode n1 = nodes.top(); // Attempts copy of nodes.top()
nodes.pop();
TreeNode n2 = nodes.top(); // Attempts copy of nodes.top()
nodes.pop();

TreeNode node;
node.value = n1.value * n2.value;
// The following two lines attempt to copy n1 and n2, respectively.
node.left = std::unique_ptr<TreeNode>(new TreeNode(n1));
node.right = std::unique_ptr<TreeNode>(new TreeNode(n2));

以下代码中还有其他一些地方,但您明白了。

请注意,您可以std::move()自己的节点来解决错误:

std::priority_queue<TreeNode> nodes;

for(int i = 0; i < 10; i++)
{
    TreeNode node;
    node.value = i;
    // Use emplace to directly-construct the element in the queue.
    nodes.emplace(std::move(node));
}

// ...

// priority_queue<T>::top() gives us a const reference; we have to cast
// the const-ness away (which is legal in this case) to move from it.
// See http://stackoverflow.com/a/20149745/501250
TreeNode n1{std::move(const_cast<TreeNode &>(nodes.top()))};
nodes.pop();
TreeNode n2{std::move(const_cast<TreeNode &>(nodes.top()))};
nodes.pop();

TreeNode node;
node.value = n1.value * n2.value;
node.left = std::unique_ptr<TreeNode>(new TreeNode(std::move(n1)));
node.right = std::unique_ptr<TreeNode>(new TreeNode(std::move(n2)));