插入一个基本的单向链表节点似乎破坏了我的 c++ 代码?

Inserting a basic singly linked list node seems to break my c++ code?

本文关键字:节点 坏了 我的 代码 c++ 链表 一个 插入      更新时间:2023-10-16

单链表和节点类以及main函数的开始,我在其中编写了代码功能的简要概述。问题出在main函数即将结束时。我写了"..."代替我认为不相关的代码,因为它只是解析字符串并将它们分配给string temp_hold[3]数组。

#include <bits/stdc++.h>
using namespace std;
class Node {
public:
string value;
string attr;
string tagname;
Node *next;
Node(string c_tagname, string c_attr, string c_value) {
this->attr = c_attr;
this->value = c_value;
this->tagname = c_tagname;
this->next = nullptr;
}
};
class SinglyLinkedList {
public:
Node *head;
Node *tail;
SinglyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void insert_node(string c_tagname, string c_attr,string c_value) {
Node *node = new Node(c_tagname,c_attr, c_value);
if (!this->head) {
this->head = node;
} else {
this->tail->next = node;
}
this->tail = node;
}
};
int main(int argc, char **argv) {
/* storage is a vector holding pointers to the linked lists
linked lists are created and the linked list iterator sll_itr is incremented when
previous line begins with '</' and the currentline begins with '<'
linked lists have nodes, which have strings corresponding to tagname, value, and attribute
*/
SinglyLinkedList *llist = new SinglyLinkedList();
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
string temp_hold[3];
// to determine new sll creation
bool prev = false;
bool now = false;

//input
int num1, num2;
cin >> num1; cin >> num2;
//read input in 
for (int i = 0; i <= num1; ++i) {
string line1, test1;
getline(cin, line1);
test1 = line1.substr(line1.find("<") + 1);
//determine to create a new linked list or wait
if (test1[0] == '/') {  
prev = now;
now = true; 
} else {
//make a node for the data and add to current linked list
if (i > 0) {    
prev = now;
now = false;
//if last statement starts with '</' and current statment starts with '<' 
// then start a new sll and increment pointer to vector<SinglyLinkedList*>
if (prev && !now) { 
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp);
sll_itr++;
}
}   
//parse strings from line
int j = 0;
vector<string> datastr;
vector<char> data;
char test = test1[j];
while (test) {  
if (isspace(test) || test == '>') {
string temp_for_vect(data.begin(),data.end());
if (!temp_for_vect.empty()) {
datastr.push_back(temp_for_vect);
}
data.clear();
} else
if (!isalnum(test)) {
} else {
data.push_back(test);
}
j++;
test = test1[j];
} 
//each node has 3 strings to fill
int count = 0;
for (auto itrs = datastr.begin(); itrs!=datastr.end(); ++itrs) {
switch (count) {
case 0:
temp_hold[count]=(*itrs);
break;
case 1:
temp_hold[count]=(*itrs);
break;
case 2:
temp_hold[count]=(*itrs);
break;
default:
break;
}
count++;
}
}
cout << "before storing node" << endl;
(*sll_itr)->insert_node(temp_hold[0], temp_hold[1], temp_hold[2]);
cout << "after" << endl;
} 
cout << "AFTER ELSE" << endl;
return 0;
}

这是破坏代码的行。auto sll_itr被取消引用,这意味着*sll_itr现在是一个SinglyLinkedList*,我们可以调用insert_node(string, string, string)将节点添加到当前链表中。但是,当我保留该行时,else 语句大括号之后的任何内容都不会运行,这意味着cout<<"AFTER ELSE"<< endl;不会触发。如果我删除insert_node行,则程序运行cout<<"AFTER ELSE"<< endl;我不确定问题是什么。

(*sll_itr)->insert_node(temp_hold[0],temp_hold[1],temp_hold[2]);
cout << "after" << endl;
} //NOT HANGING. This closes an else statement.
cout << "AFTER ELSE" << endl;
return 0;
} 

编译为g++ -o myll mylinkedlist.cpp然后myll.exe < input.txtinput.txt包含

8 3
<tag1 value = "HelloWorld">
<tag2 name = "Name2">
</tag2>
</tag1>
<tag5 name = "Name5">
</tag5>
<tag6 name = "Name6">
</tag6>

你的链表不是问题,至少不是这里的问题。

正在制造灾难的秘诀:保留、引用和潜在地操作动态集合上的迭代器,这可能会使容器修改的迭代器失效。您的代码就是这样做的。扔掉所有之间的拐杖:

vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
....
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp); // HERE: INVALIDATES sll_iter on internal resize
sll_itr++; // HERE: NO LONGER GUARANTEED VALID; operator++ CAN INVOKE UB

要解决此问题,您有两种选择:

  • 使用不会使push_back上的迭代器失效的容器。实际上只有两个序列容器符合该描述:std::forward_liststd::list
  • 将您的算法更改为按索引引用,而不是通过迭代器引用。 即,让你的循环迭代,直到索引元素到达容器末端,然后中断。

可以在此处找到有关使指针和迭代器无效/不使指针和迭代器失效的容器的精彩讨论。值得一读。