[英]How is it possible to pass move-only types (e.g. std::unique_ptr) by value?
[英]How to initialize unique_ptr of nested structs (e.g. for binary trees)
在现代C ++中,通常建议在处理二叉树时使用unique_ptr
来明确子树的所有权。 例如, 编程面试要素建议:
template <typename T>
struct Node {
T data;
unique_ptr<Node<T>> left, right;
};
我只是在学习C ++ 11功能,并且想知道初始化与特定结构相对应的二叉树的最便捷方法是什么。 我的用例是为特定的树编写单元测试。 例如,我要生成此树:
5
/ \
3 4
/ \
1 2
下面的方法确实有效,但确实很麻烦:
// first attempt: temporary variables & high syntactic noise
unique_ptr<Node<int>> tmp_n1(new Node<int>{1, nullptr, nullptr});
unique_ptr<Node<int>> tmp_n2(new Node<int>{2, nullptr, nullptr});
unique_ptr<Node<int>> tmp_n3(new Node<int>{3, move(tmp_n1), move(tmp_n2)});
unique_ptr<Node<int>> tmp_n4(new Node<int>{4, nullptr, nullptr});
unique_ptr<Node<int>> root(new Node<int>{5, move(tmp_n3), move(tmp_n4)});
我希望实现的是摆脱临时变量,并在一个嵌套语句中初始化树。 如果代码结构类似于树结构,那将是很好的。 但是,以下尝试失败,并出现“无法转换”错误:
// second attempt: nested, but still a lot of syntax noise
unique_ptr<Node<int>> root(new Node<int>{5,
new unique_ptr<Node<int>>(new Node<int>{3,
new unique_ptr<Node<int>>(new Node<int>{1, nullptr, nullptr}),
new unique_ptr<Node<int>>(new Node<int>{2, nullptr, nullptr})
}),
new unique_ptr<Node<int>>(new Node<int>{4, nullptr, nullptr})
});
有什么想法如何以语法简洁,简洁,灵活的方式编写此类树初始化?
这是一个使用C ++ 14 make_unique
的解决方案,其左子树和右子树的默认参数设置为nullptr
,以避免原始的new
:
#include <iostream>
#include <memory>
template<class T>
struct Node;
template<class T>
using node_ptr = std::unique_ptr<Node<T>>;
template<class T>
struct Node
{
T data;
node_ptr<T> left, right;
Node(T const& value, node_ptr<T> lhs, node_ptr<T> rhs)
:
data(value), left(std::move(lhs)), right(std::move(rhs))
{}
};
template<class T>
auto make_node(T const& value, node_ptr<T> lhs = nullptr, node_ptr<T> rhs = nullptr)
{
return std::make_unique<Node<T>>(value, std::move(lhs), std::move(rhs));
}
template<class T>
void print_tree(Node<T> const& node)
{
std::cout << "{ ";
std::cout << node.data;
if (node.left) {
std::cout << ", ";
print_tree(*(node.left));
}
if (node.right) {
std::cout << ", ";
print_tree(*(node.right));
}
std::cout << " }";
}
int main()
{
auto const root = make_node(
5,
make_node(
3,
make_node(1),
make_node(2)
),
make_node(4)
);
print_tree(*root);
}
更新 :感谢@ Jarod42的评论,我将print_tree的签名print_tree
为采用Node<T> const&
这样它现在是const正确的,您不必在任何地方键入.get()
。 我还做了一个模板别名 node_ptr<T>
以在实现中对unique_ptr<Node<T>>
具有更简洁的表示。
感谢@Satus的评论,我得以提出一些(现在正在工作)帮助程序功能:
template <typename T>
unique_ptr<Node<T>> new_node(const T& data,
unique_ptr<Node<T>> left = nullptr,
unique_ptr<Node<T>> right = nullptr) {
return unique_ptr<Node<int>>(new Node<int>{data, move(left), move(right)});
}
这样可以构造一个像这样的树:
auto root =
new_node(5,
new_node(3,
new_node(1),
new_node(2)),
new_node(4)
);
我仍然不确定这是否是一个更有经验的C ++ 11程序员会做的事情,但是对我来说这是朝着正确方向迈出的一步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.