我正在尝试将数据放入std::map
。以下是我的尝试(从原始来源修剪,但绝对给出了想法):
template<typename T> class trie {
private:
std::map<typename T::value_type, std::unique_ptr<trie<T>>> children;
std::unique_ptr<trie<T>> parent;
// Later
public:
trie(const trie<T>& other, trie<T>* const parent) :
parent{parent}
{
for(auto const &it : other.children)
children.emplace(it.first, {*it.second});
}
};
错误如下:
trie.h: In instantiation of ‘trie<T>::trie(const trie<T>&, trie<T>*) [with T = std::basic_string<char>]’:
main.cpp:7:23: required from here
trie.h:90:3: error: no matching function for call to ‘std::map<char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > >, std::less<char>, std::allocator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > > >::emplace(const char&, <brace-enclosed initializer list>)’
children.emplace(it.first, {*it.second});
^
trie.h:90:3: note: candidate is:
In file included from /usr/include/c++/4.8.1/map:61:0,
from trie.h:4,
from main.cpp:2:
/usr/include/c++/4.8.1/bits/stl_map.h:540:2: note: std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::emplace(_Args&& ...) [with _Args = {}; _Key = char; _Tp = std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > >; _Compare = std::less<char>; _Alloc = std::allocator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > >; typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator = std::_Rb_tree_iterator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > >]
emplace(_Args&&... __args)
^
/usr/include/c++/4.8.1/bits/stl_map.h:540:2: note: candidate expects 0 arguments, 2 provided
所以我的问题是:
如何正确初始化地图元素,目标是指向特里的深层副本,没有不必要的副本/移动?
提前致谢!
答案 0 :(得分:4)
通过传递{*it.second}
作为该值的初始化,您实际上是在尝试使用std::unique_ptr<trie<T>>
初始化trie<T>
。我相信你正在寻找这个:
public:
trie(const trie<T>& other, trie<T>* const parent) :
parent{parent}
{
for(auto const &it : other.children) {
// Separate creation of unique_ptr for exception safety, thanks to @DanielFrey
std::unique_ptr<trie<T>> p(new trie<T>(*it.second));
children.emplace(it.first, std::move(p));
}
}
请注意,您还必须提供复制构造函数,因为默认的复制构造函数已被删除,因为您的类具有不可复制的成员。
与此问题无关,但您应该重新考虑您的设计:您很可能拥有所有权循环。如果trie<T>
将unique_ptr
存储到其子级中并将这些unique_ptr
存储回其父级,则会出现双重删除错误。将其中一个(可能是指向父项的指针)转换为原始指针。没有参与所有权的情况下,原始指针可以用于观察。
答案 1 :(得分:4)
你需要
for(auto const &it : other.children) {
std::unique_ptr<trie<T>> element(new trie<T>(*it.second));
children.emplace(it.first, std::move(element));
}
以防止在emplace
引发异常时发生资源泄漏。如果可用(C ++ 14),您可以将代码简化为
for(auto const &it : other.children) {
children.emplace(it.first, std::make_unique<trie<T>>(*it.second));
}
根据所有智能指针的经验法则,您始终使用std::make_*
或,您必须使用单独的行来创建每个智能指针。