2

我正在尝试将数据放入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

所以我的问题是:

如何正确初始化 map 元素,目标是指向 trie 的深层副本,并且没有不必要的副本/移动?

提前致谢!

4

2 回答 2

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_* 必须使用单独的行来创建它们中的每一个。

于 2013-10-13T10:07:20.397 回答
4

通过{*it.second}作为值的初始化程序传递,您实际上是在尝试std::unique_ptr<trie<T>>用 a 初始化 a 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));
    }
}

请注意,您还必须提供一个复制构造函数,因为默认的构造函数已被删除,因为您的类具有不可复制的成员。


与问题无关,但您应该重新考虑您的设计:您很可能有一个所有权循环。如果 atrie<T>将a 存储unique_ptr到其子级,而这些将 a 存储unique_ptr回其父级,则会出现双重删除错误。将其中之一(可能是指向父级的指针)转换为原始指针。原始指针可以在不参与所有权的情况下进行观察。

于 2013-10-13T09:30:28.740 回答