C++ []运算符访问无序的_映射时出错
我在一张无序的地图上偶然发现了一个奇怪的问题 首先,我生成了一个无序的映射,并在表中插入了一条记录(“Bob”,Person(1,“Bob”))。然后,我尝试使用带有键“Bob”的[]运算符访问该记录,但出现了一个错误 代码如下:C++ []运算符访问无序的_映射时出错,c++,c++11,g++,unordered-map,C++,C++11,G++,Unordered Map,我在一张无序的地图上偶然发现了一个奇怪的问题 首先,我生成了一个无序的映射,并在表中插入了一条记录(“Bob”,Person(1,“Bob”))。然后,我尝试使用带有键“Bob”的[]运算符访问该记录,但出现了一个错误 代码如下: #include<iostream> #include<unordered_map> using namespace std; class Person { public: int play; stri
#include<iostream>
#include<unordered_map>
using namespace std;
class Person
{
public:
int play;
string name;
Person(int p, string n):play(p), name(n) {}
};
int main()
{
unordered_map<string,Person> test;
test.insert(std::make_pair("haha",Person(1,"haha")));
cout<<test["haha"].name<<endl;
return 0;
}
#包括
#包括
使用名称空间std;
班主任
{
公众:
智力游戏;
字符串名;
Person(int p,string n):play(p),name(n){}
};
int main()
{
无序图试验;
测试插入(标准:配对(“哈哈”,人(1,“哈哈”));
cout问题不在于[]运算符。实际问题在于编译器执行以下行时:
cout<<test["haha"].name<<endl;
cout无序映射的映射类型必须是operator[]
下的DefaultConstructible。即,如果您希望能够使用operator[]
,Person()必须具有默认构造函数
或者,使用at():
intmain()
{
标准:无序图试验;
测试插入(标准:配对(“哈哈”,人(1,“哈哈”));
std::cout正如注释和另一个答案中所解释的,可能需要创建一个对象:如果没有为键找到任何对象,它将插入一个默认构造的元素并返回该元素
如果这不是您想要的,您可以简单地尝试查找元素,并仅在存在时使用它:
auto it = map.find("haha");
if(it != map.end()) {
cout << it->second.name;
}
唯一的不便是您必须通过person::second.play
访问数据,如play
。解决此问题的一种方法是定义
struct person : private personMap::value_type
{
using base = personMap::value_type;
// must not add new data members to avoid slicing
personData& data() { return base.second; }
personData const& data() const { return base.second; }
int play() const { return data().play; }
string const&name() const { return base.first; }
};
auto fred = static_cast<person&>(map["fred"]);
struct person:private personMap::value\u type
{
使用base=personMap::value\u类型;
//不得添加新数据成员以避免切片
personData&data(){return base.second;}
personData常量&data()常量{return base.second;}
int play()常量{return data().play;}
字符串常量&name()常量{return base.first;}
};
自动弗雷德=静态施法(映射[“弗雷德]);
给出的答案是正确的。我只想补充一下为什么在这种情况下编译器不提供默认构造函数:
从网上
如果为类类型(struct、class或union)提供了任何类型的用户声明构造函数,则编译器将始终将默认构造函数声明为其类的内联公共成员
但是,如果提供了任何类型的用户声明构造函数,编译器将而不是生成默认构造函数
如果存在一些用户声明的构造函数,用户仍然可以强制编译器自动生成默认构造函数,而默认构造函数将以关键字default隐式声明
因此,您可以在类的公共部分的代码中添加以下行,您的代码将按预期工作:
Person() = default;
您需要包含字符串头,并且需要Person的默认构造函数。test[“haha”]。name
可能需要构造一个对象,如果没有默认构造函数,您就会遇到问题。您可以在错误中看到:没有匹配的函数来调用“Person::Person()
完成。感谢您的帮助。我尚未考虑[]的可能需求运算符。这确实是个问题。我不得不对这篇文章投反对票,因为编译器清楚地说明了问题所在,但你还是这样问。谢谢。我错误地忽略了这条规则,认为我的代码不会构造新的Person对象,这是根本原因。非常有用且有见地。非常感谢!是的,我注意到了这条规则如果找不到该键的任何元素,它将插入一个默认构造的元素并返回该元素“无序映射。但我认为我的程序可以找到密钥,因此我忽略了编译器的必要检查,这是根本原因。谢谢。这是一个重要的教训。是的,我忽略了规则,并收到了编译器的投诉。谢谢。@ronald您可以通过使用insert、emplace、find和at来避免实现默认构造函数。”这是非常重要的一课。
auto it = map.find("haha");
if(it != map.end()) {
cout << it->second.name;
}
struct personData
{
int play; // etc
};
using personMap = unordered_map<string,personData>;
using person = personMap::value_type;
struct person : private personMap::value_type
{
using base = personMap::value_type;
// must not add new data members to avoid slicing
personData& data() { return base.second; }
personData const& data() const { return base.second; }
int play() const { return data().play; }
string const&name() const { return base.first; }
};
auto fred = static_cast<person&>(map["fred"]);
Person() = default;