用户定义数据类型的c ++ unordered_map

时间:2015-02-21 17:46:03

标签: c++ unordered-map

我正在编写此代码以查找图表的连接组件。

    using namespace std;
    struct node;
    typedef list<node> AdjList;
    struct node
    {
        bool visited;
        string  name;
        AdjList adjlist;
        node(string name1):name(name1),visited(false){}
        node(const string& a):name(a),visited(false){}
    };
    typedef node node;




    class graph
    {
    int nonodes;
    unordered_map<string,node> vertices;
    public:
    graph(int v):nonodes(v){}
    void addrelation(string a , string b);
    void addaccount(string name);
    void dfs();
    };

void  graph::addaccount(string name)
{
    unordered_map<string,node>::iterator it = vertices.find(name);

    if(it!=vertices.end())
    {
        cout<<"account already exists"<<endl;
    }
    else
    {
        cout<<"creating a new account"<<endl;
        node* nnode=new node(name);
        vertices[name] = *nnode;
    }

}

对于这些行,

    cout<<"creating a new account"<<endl;
    node* nnode=new node(name);
    vertices[name] = *nnode;

我收到以下错误。 toposort.cpp:72:从这里实例化 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/tr1_impl/hashtable_policy.h:575:错误:没有匹配功能调用'node :: node()'

当我们将已创建的成员分配给unordered_map时,unordered_map是否会在内部尝试复制它?

3 个答案:

答案 0 :(得分:2)

这是预期的行为。根据{{​​3}}

  

如果执行插入,则映射的值是值初始化的(默认为类类型构造,否则为零初始化),并返回对它的引用。

在内部,std::unordered_map的{​​{1}}需要在找不到密钥时创建数据类的新实例,并返回对它的引用。所有这些都发生在赋值之前,而正在评估表达式的左侧。这就是导致错误的默认构造函数的错误。

因此,如果您希望将map operator[]与您的值类型一起使用,则需要提供一种默认构造值对象的方法。

注1:确实会复制值。但是,它只在 operator[]之后开始。

注意2:为operator[]定义单独的按值传递构造函数没有意义,因为另一个构造函数(即struct node)完全能够处理这两种情况。

注3:动态分配节点没有意义。目前,它泄漏了内存。赋值node(const string& a)可以在没有泄漏的情况下执行相同的操作。

答案 1 :(得分:1)

unordered_mapoperator[]插入的元素值已初始化:

  

如果执行插入,则映射值将进行值初始化   (默认为类类型构造,否则为零初始化)和   返回它的引用。

然后通过赋值复制元素。

答案 2 :(得分:1)

@dasblikenlight部分解释了这个问题,但他没有 提出解决方案。插入元素的常规方法是使用 函数insert

vertices.insert( std::make_pair( name, node( name ) );

由于您的node类型具有值语义,因此不应该 new它, 只需在需要时构建它。如果你真的想保留 建筑分开:

node newNode( name );
vertices.insert( std::make_pair( name, newNode ) );

(作为一般规则,如果类型具有值语义,则它永远不应该 动态分配。有一些例外,通常用于表现 原因,但它们只是例外情况。)

最后,insert当且仅当没有元素时插入std::pair 等效键,它返回bool,其中addaccount表示 插入是否发生。所以你的整个std::pair<std::unordered_map<std::string, node>::iterator, bool> results = vertices.insert( std::make_pair( name, node( name ) ) ); if ( ! results.second ) { std::cout << "account already exists" << std::endl; } 变得简单:

std::map

(我通常使用typedef作为地图类型,以制作此类型名称 更易于管理。更不用说它允许轻松切换 不同类型的地图;除非地图非常大,你可能会发现 std::unordered_map优于[]。)

要明确value_type( key, mapped_type() ):标准说如果条目不是 存在,它插入insert(基本上使用 上面的value_type函数,其中std::pair[])。 那是调用默认构造函数的地方。 而且...插入是否发生是动态确定的,所以 编译器将尝试编译它,即使你从未使用[] 不存在的元素。如果您想支持{{1}},您必须 支持映射类型的默认构造。