为什么getNodeSuccess方法有效,但getNodeFail不起作用?

问题描述 投票:0回答:1

我对以下代码的行为感到困惑:我不理解getNodeSuccess方法为什么起作用,但是getNodeFail方法无法构建。这两种方法之间的唯一区别是,一种使用[]运算符访问地图,另一种使用at方法。我认为这两个操作都返回对地图中元素的引用,并且两者基本上应该做相同的事情。但是,当我使用[]运算符而不是at()方法时,它将尝试调用GraphNode类的默认构造函数。由于默认的构造函数是私有的,因此构建失败。

为了演示,我将GraphNode类的默认构造函数设为私有。如果我将其更改为公开,那么它将起作用。

有人可以解释这是怎么回事吗?为什么一个方法触发默认构造函数,而不触发另一个?

#include <vector>
#include <list>
#include <unordered_map>
#include <exception>

template <class T>
struct GraphNode
{
    int id;
    T data;
    std::list<int> adj; // adjacency list

    GraphNode(const int id) 
    {
        this->id = id;
    }
private:
    GraphNode() {}
};

template<class T>
struct UndirectedGraph 
{
    std::unordered_map<int, GraphNode<T>> lookup;
    std::vector<GraphNode<T>> vertices;

    void addNode(const GraphNode<T> node) 
    {
        // if the id of the node already exists, than we cannot add it
        if (lookup.find(node.id) == lookup.end())
            lookup.insert(std::make_pair(node.id, node));
        else
            throw std::runtime_error("Trying to add a node that already exists.");
    }

    void addEdge(const int source, const int destination) 
    {
        getNodeSuccess(source).adj.push_back(destination);
        getNodeSuccess(destination).adj.push_back(source);

        getNodeFail(source).adj.push_back(destination);
        getNodeFail(destination).adj.push_back(source);
    }

    GraphNode<T>& getNodeSuccess(const int id)
    {
        if (lookup.find(id) == lookup.end())
            throw std::runtime_error("Trying to retrieve a node that doesn't exist");

        return lookup.at(id);
    }

    GraphNode<T>& getNodeFail(const int id)
    {
        if (lookup.find(id) == lookup.end())
            throw std::runtime_error("Trying to retrieve a node that doesn't exist");

        return lookup[id];
    }
};

int main(int argc, char* argv[]) 
{
    UndirectedGraph<int> graph;

    graph.addNode(GraphNode<int>(1));
    graph.addNode(GraphNode<int>(3));
    graph.addEdge(1, 3);

    return 0;
}
c++ unordered-map accessor default-constructor
1个回答
0
投票

operator[]将使用该键为return对值的引用,或者使用默认构造函数创建一个引用,然后将其插入,而return将对新构造的值进行引用。因此,您的问题是operator[]必须至少能够调用默认构造函数,即使您知道密钥将始终存在

如果您只想查询unordered_map中是否有东西,则对find的使用已经结束。

GraphNode<T>& getNodeFail(const int id)
{
    auto it = lookup.find(id);
    if (it == lookup.end())
        throw std::runtime_error("Trying to retrieve a node that doesn't exist");
    return it->second;
}

由于您已经用find做过一次工作,因此,这也将节省您更多的查找。

© www.soinside.com 2019 - 2024. All rights reserved.