C ++将元素分配给映射值时访问错误

时间:2020-05-31 19:35:54

标签: c++ dictionary hashmap exc-bad-access

所以这个问题解释了问题...

背景:

我正在尝试从HackerRank解决this problem

它基本上是一个html标签解析器。保证有效输入,属性仅是字符串。

我的方法

我创建了一个自定义s = components.size(c) 类,该类可以存储其他Tag的{​​{1}}以及属性map<string,Tag>。解析似乎工作正常。

问题

在查询过程中,以下查询/ html组合出现了Tag错误:

map<string,string>

当我尝试从BAD_ACCESS访问4 1 <a value = "GoodVal"> <b value = "BadVal" size = "10"> </b> </a> a.b~size 标记时发生错误。具体来说,它位于下面的第b行118中。

代码

a

我尝试过的事情

要解决此问题,只需在上面的行中将t=t.tags[tag_name]定义为新变量,然后再进行#include <cmath> #include <cstdio> #include <vector> #include <iostream> #include <algorithm> #include <sstream> #include <map> #include <stack> using namespace std; class Tag { public: Tag(){}; Tag(string name):name(name){}; string name; map<string,Tag> tags = map<string, Tag>(); map<string,string> attribs=map<string,string>(); }; int main() { int lines, queries; std::cin>>lines>>queries; std:string str; getline(cin, str); stack<string> open; auto tags = map<string, Tag>(); for (int i = 0; i < lines; i++) { getline(cin, str); if (str.length()>1){ // If it's not </tag>, then it's an opening tag if (str[1] != '/') { // Parse tag name auto wordidx = str.find(" "); if (wordidx == -1) { wordidx = str.length()-1.f; } string name = str.substr(1,wordidx-1); auto t = Tag(name); string sub = str.substr(wordidx); auto equalidx=sub.find("="); // Parse Attributes while (equalidx != std::string::npos) { string key = sub.substr(1,equalidx-2); sub = sub.substr(equalidx); auto attrib_start = sub.find("\""); sub = sub.substr(attrib_start+1); auto attrib_end = sub.find("\""); string val = sub.substr(0, attrib_end); sub = sub.substr(attrib_end+1); t.attribs[key] = val; equalidx=sub.find("="); } // If we're in a tag, push to that, else push to the base tags if (open.size() == 0) { tags[name] = t; } else { tags[open.top()].tags[name]=t; } open.push(name); } else { // Pop the stack if we reached a closing tag auto wordidx = str.find(">"); string name = str.substr(2,wordidx-2); // Sanity check, but we're assuming valid input if (name.compare(open.top())) { cout<<"FUCK"<<name<<open.top()<<endl; return 9; } open.pop(); } } else { std::cout<<"FUCK\n"; } } // // Parse in queries // for (int i = 0; i < queries; i++) { getline(cin, str); Tag t = Tag(); bool defined = false; auto next_dot = str.find("."); while (next_dot!=string::npos) { string name = str.substr(0,next_dot); if (defined && t.tags.find(name) == t.tags.end()) { //TAG NOT IN T cout<<"Not Found!"<<endl; continue; } t = !defined ? tags[name] : t.tags[name]; defined = true; str = str.substr(next_dot+1); next_dot = str.find("."); } auto splitter = str.find("~"); string tag_name = str.substr(0,splitter); string attrib_name = str.substr(splitter+1); if (!defined) { t = tags[tag_name]; } else if (t.tags.find(tag_name) == t.tags.end()) { //TAG NOT IN T cout<<"Not Found!"<<endl; continue; } else { t = t.tags[tag_name]; } // T is now set, check the attribute if (t.attribs.find(attrib_name) == t.attribs.end()) { cout<<"Not Found!"<<endl; } else { cout<<t.attribs[attrib_name]<<endl; } } return 0; } ,为什么会这样呢?

此外,以下查询也将失败:Tag x = t.tags[tag_name];,但在尝试获取a.tags [“ b”]时在第99行失败。不知道为什么。我本来只是要进行上述修正,但这似乎是我做错了一个很大的核心问题。

我建议在IDE上运行它,并验证解析的确正确。

1 个答案:

答案 0 :(得分:1)

t=t.tags[tag_name]

此表达式是不安全的,因为您正在将对象拥有的对象复制分配给拥有的对象。

考虑此行会发生什么:

  1. 执行地图查找并返回一个Tag&
  2. 您尝试将其复制分配给t,从而调用隐式复制辅助运算符。
  3. 该运算符从位于t.tags中的复制源的<{1}}属性的tags属性中复制t.tags

结果是您要复制到t中的对象在该副本的中间被破坏了。这将导致不确定的行为,并且说实话,立即崩溃是最佳结果,因为它告诉您问题的确切出处。 (这种问题经常在程序的某个时刻出现,这时您已经失去了找出导致UB的原因的必要状态。)

一种解决方法是将源对象移至临时对象,然后在t上移动该临时对象:

t = Tag{std::move(t.tags[tag_name])};

这会在我们尝试将其分配到t之前,从t 中提取我们要分配给t的数据。然后,当t的赋值运算符去替换t.tags时,您要分配给t的数据就不再存在。

但是,这种整体方法涉及许多不必要的复制。最好将t声明为Tag const *t; -如果它是标记的 pointer 。然后,您只需移动指针即可指向数据结构中的其他标签,而无需进行复制。


旁注:前几天我刚遇到这个问题!这里有一个提示可能会帮助您简化事情:您实际上是否需要标签结构?有没有比嵌套标记更简单的查找结构类型?