我正在编写此代码以查找图表的连接组件。
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是否会在内部尝试复制它?
答案 0 :(得分:2)
这是预期的行为。根据{{3}}
如果执行插入,则映射的值是值初始化的(默认为类类型构造,否则为零初始化),并返回对它的引用。
在内部,std::unordered_map
的{{1}}需要在找不到密钥时创建数据类的新实例,并返回对它的引用。所有这些都发生在赋值之前,而正在评估表达式的左侧。这就是导致错误的默认构造函数的错误。
因此,如果您希望将map operator[]
与您的值类型一起使用,则需要提供一种默认构造值对象的方法。
注1:确实会复制值。但是,它只在 operator[]
之后开始。
注意2:为operator[]
定义单独的按值传递构造函数没有意义,因为另一个构造函数(即struct node
)完全能够处理这两种情况。
注3:动态分配节点没有意义。目前,它泄漏了内存。赋值node(const string& a)
可以在没有泄漏的情况下执行相同的操作。
答案 1 :(得分:1)
答案 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}},您必须
支持映射类型的默认构造。