gpt4 book ai didi

c++ - 'delete' 在 clang 中完美编译时在 g++ 中抛出错误

转载 作者:行者123 更新时间:2023-11-27 22:38:20 25 4
gpt4 key购买 nike

所以我实现了一个标准的链表,它在 clang 中编译和运行完美。但是,g++ 抛出了很多错误,并且在消除了常见的内存泄漏之后,出现了一个没有任何书籍/文档/教程可以帮助解决的错误-

struct token{
string data;
string id = "n";
void print(){
cerr<<"| "<<data<<" | ";
}
};

struct node{
token data;
node *next = nullptr;
void print(){
cerr<<" ||| "<<this<<" | "<<data.data<<" | "<<next<<" ||| ";
}
};

class list{
friend class queue;
friend class stack;
public:
node *head = nullptr;
node *tail = nullptr;

void insert(token incoming_data){
if (head == nullptr){
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = nullptr;
head = new_node;
tail = new_node;
new_node = nullptr;
}
else{
node *new_node = new node;
new_node->data = incoming_data;
tail->next = new_node;
new_node->next = nullptr;
tail = new_node;
new_node = nullptr;
}
}

void del(){
cerr<<"List before deletion is ";
print();
cerr<<"\n";
cerr<<"Head is at "<<head;
cerr<<"\n";
if (head == nullptr){
cerr<<"List is empty\n";
return;
}
else if (head->next == nullptr){
tail = nullptr;
cerr<<endl<<"Deleting object at "<<head<<endl;
delete head;
head = nullptr; //keep an eye on this

}
else{
node *temp = head;
head = temp->next;
cerr<<endl<<"Deleting object at "<<temp<<endl;
delete temp;
temp = nullptr;
}
cerr<<"List after deletion is ";
print();
cerr<<"\n";
}

~list(){
cerr<<"Destructor calling delete"<<endl;
while (not(head == nullptr)){
del();
}
}
void insert_front(token incoming_data){
if (head == nullptr){
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = nullptr;
head = new_node;
tail = new_node;
new_node = nullptr;
}
else{
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = head;
head = new_node;
new_node = nullptr;
}
}

};

现在,它可以独立运行。使用它实现的堆栈和队列工作得很好。但是,在析构函数试图调用它时的某个时刻,会发生这种情况-

Destructor calling delete

List before deletion is
||| 0x100409bc0 | 55 | 0x100431890 ||| --> ||| 0x100431890 | 5 | 0x100504830 ||| --> ||| 0x100504830 | + | 0x0 ||| --> NULL

Head is at 0x100409bc0
Deleting object at 0x100409bc0
test shunting yard (76600,0x10039e380) malloc: *** error for object 0x100409bc0: pointer being freed was not allocated

节点以|||格式打印本节点地址 |资料 |下一个节点的地址||

是的,每个节点都是使用“new”动态创建的。此外,同一个析构函数和 del 函数在同一个程序中可以完美运行多次,但对于一个特定的实例,会失败。

在其他具有相同错误的堆栈溢出问题中,指针没有指向任何东西,但是这里显然有一个对象可以在有问题的指针处删除。


编辑:它是使用 Shunting-Yard 实现的 RPN 解析,这是完整的代码-

    #include <iostream>
#include <string.h>
#include<cmath>
using namespace std;
struct token{
string data;
string id = "n";
void print(){
cerr<<"| "<<data<<" | ";
}
};

struct node{
token data;
node *next = nullptr;
void print(){
cerr<<" ||| "<<this<<" | "<<data.data<<" | "<<next<<" ||| ";
}
};

class list{
friend class queue;
friend class stack;
public:
node *head = nullptr;
node *tail = nullptr;

void insert(token incoming_data){
if (head == nullptr){
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = nullptr;
head = new_node;
tail = new_node;
new_node = nullptr;
}
else{
node *new_node = new node;
new_node->data = incoming_data;
tail->next = new_node;
new_node->next = nullptr;
tail = new_node;
new_node = nullptr;
}
}
void print(){
cerr<<endl;
if (head == nullptr){
cerr<<"List is empty";
}
else{
node *active_ptr = head;
while(active_ptr!=nullptr){
active_ptr->print();
cerr<<" --> ";
active_ptr = (*active_ptr).next;
}
cerr<<"NULL\n";
}
}
void del(){
cerr<<"List before deletion is ";
print();
cerr<<"\n";
cerr<<"Head is at "<<head;
cerr<<"\n";
if (head == nullptr){
cerr<<"List is empty\n";
return;
}
else if (head->next == nullptr){
tail = nullptr;
cerr<<endl<<"Deleting object at "<<head<<endl;
delete head;
head = nullptr; //keep an eye on this

}
else{
node *temp = head;
head = temp->next;
cerr<<endl<<"Deleting object at "<<temp<<endl;
delete temp;
temp = nullptr;
}
cerr<<"List after deletion is ";
print();
cerr<<"\n";
}
bool is_empty(){
if (head == nullptr){
return true;
}
else return false;
}

token first_elem(){
return head->data;
}

~list(){
cerr<<"Destructor calling delete"<<endl;
while (not(head == nullptr)){
del();
}
}
void insert_front(token incoming_data){
if (head == nullptr){
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = nullptr;
head = new_node;
tail = new_node;
new_node = nullptr;
}
else{
node *new_node = new node;
new_node->data = incoming_data;
new_node->next = head;
head = new_node;
new_node = nullptr;
}
}

};

class queue{
public:
list l_queue_list;

void push(token incoming_data){
l_queue_list.insert(incoming_data);
}
void pop(){
if(is_empty()){
return;
}
l_queue_list.del();
}
token peek(){
return (l_queue_list.first_elem());
}
void print(){
l_queue_list.print();
}
bool is_empty(){
if(l_queue_list.is_empty())
return true;
else return false;
}
};
class stack{
public:
list l_stack_list;
void push(token incoming_data){
l_stack_list.insert_front(incoming_data);
}
void pop(){
if(is_empty()){
return;
}
l_stack_list.del();
}
token peek(){
return l_stack_list.first_elem();
}
void print(){
l_stack_list.print();
}
bool is_empty(){
if(l_stack_list.is_empty())
return true;
else return false;
}
};

class Thermostat{
public:
bool heating, cooling, user_setting, valid_command = true; //command is valid until an exception is thrown
int current_temp, desired_temp;
Thermostat(string cmd){
try{
lexer(&cmd);
logic();
}
catch(...){
raise_error(7);
}
}
private:
void lexer(string *cmd) {
string command = *cmd;
int pos = 0, len = (int)command.length();
char *start = NULL, *end = NULL;
if (!(command.find_first_not_of("TtCcHh0123456789+-") == string::npos)){
raise_error(0);
return;
}
if (command[pos] != 'T' and command[pos] !='t' and !(isdigit(command[pos+1]))){
raise_error(1);
return;
}
else{
pos++;
if(!isdigit(command[pos])){
raise_error(2);
return;
}
start = &command[pos];
while(isdigit(command[pos]) and pos<len)
pos++;
end = &command[--pos];
current_temp = parse_digits(start, end);
pos++;
if (pos == len){
user_setting = false;
return;
}
else if(command[pos]!='H' and command[pos]!='h' and command[pos]!='C' and command[pos]!='c'){
raise_error(3);
return;
}
else{
user_setting = true;
if(command[pos] == 'H' or command[pos] == 'h')
heating = true;
if(command[pos] == 'C' or command[pos] == 'c')
cooling = true;
pos++;
if(!isdigit(command[pos])){
raise_error(4);
return;
}
desired_temp = parse_expression(pos, cmd);
}
}
}
int parse_digits(char *start, char *end){
int temperature = 0, place_value = 0;
for(; end>=start; end--){
temperature = temperature + (*end-'0') * pow(10,place_value);
place_value++;
}
return temperature;
}
queue generate_expression_queue(int pos, string *cmd){ //Generates the expression queue for Shunting-Yard to work on
string command = *cmd, literal ="";
queue exp_queue;
int flag = pos;
for(; pos<=command.length(); pos++){
if(command[pos] == '+' or command[pos]=='-'){
literal = command.substr(flag, (pos-flag)); //Literals are numbers precceded by operators
token tok1, tok2;
tok1.data = literal;
tok2.data =(string(1, command[pos])); //Converting the operator to string-type inline
tok2.id = "o";
exp_queue.push(tok1);
exp_queue.push(tok2);
flag = pos+1;
}
}
token tok3;
tok3.data = (command.substr(flag, (command.length()-flag))); //token 3 carries the last digits which aren't succeeded by an operator
exp_queue.push(tok3);
return exp_queue;
}
queue shunting_yard(queue exp_queue) { //Simplified execution of shunting-yard because expressions don't have parantheses or operator precedence
queue output;
stack ops;
token temp;
while(!exp_queue.is_empty()){
if(exp_queue.peek().id=="n"){
temp = exp_queue.peek();
output.push(temp);
exp_queue.pop();
}
else if(exp_queue.peek().id=="o"){
if(ops.is_empty()){
temp = exp_queue.peek();
ops.push(temp);
exp_queue.pop();
}
else {
temp = ops.peek();
output.push(temp);
ops.pop();
temp = exp_queue.peek();
ops.push(temp);
exp_queue.pop();
}
}
}
while(!ops.is_empty()){
temp = ops.peek();
output.push(temp);
ops.pop();
}
return output;
}
token eval(token op1, token op2, token operation){// Evaluate binary operation of + or -
int num1, num2, result;
token output;
try {
num1 = stoi(op1.data);
num2 = stoi(op2.data);
if(num1 == 0 or num2 == 0){ // Increment or Decrement by 0 not allowed
raise_error(6);
return output;
}
if(operation.data == "+"){
result = num1 + num2;
output.data = to_string(result);
return output;
}
else if (operation.data == "-"){
result = num1 - num2;
output.data = to_string(result);
return output;
}
else{
raise_error(5);
return output;
}
}
catch(...){
raise_error(5);
return output;
}
}

int reverse_polish_parse(queue exp_queue){ //RPN parsing algorithm
stack ops_stack;
token op1, op2, operation, temp;
while(!exp_queue.is_empty()){
if(exp_queue.peek().id == "n"){
temp = exp_queue.peek();
ops_stack.push(temp);
exp_queue.pop();
}
else if(exp_queue.peek().id == "o"){
op1 = ops_stack.peek();
ops_stack.pop();
op2 = ops_stack.peek();
ops_stack.pop();
operation = exp_queue.peek();
exp_queue.pop();
token x = eval(op2, op1, operation);
ops_stack.push(eval(op2,op1,operation));
}
}
try{
return (stoi(ops_stack.peek().data));
}
catch(...){
raise_error(5);
return -1000;
}
}
int parse_expression(int pos, string*cmd){//
queue exp_queue = generate_expression_queue(pos, cmd);
exp_queue = shunting_yard(exp_queue);
return reverse_polish_parse(exp_queue);
}
void raise_error(int id){
valid_command = false;

switch (id) {
case 0:
cerr<<"Ilegal characters\n";
break;
case 1:
cerr<<"First letter of command must be T or t\n";
break;
case 2:
cerr<<"T must be followed by current temperature\n";
break;
case 3:
cerr<<"Current temperature must be followed by setting\n";
break;
case 4:
cerr<<"Setting must be followed by a vaid expression\n";
break;
case 5:
cerr<<"Error parsing expression token. Please check\n";
break;
case 6:
cerr<<"Increment or Decrement should be more than 0\n";
break;
case 7:
cerr<<"Please don't walk into a bar and try to order -5 beers. Thanks :) \n";
break;
default:
break;
}

}
void logic(){
if (heating and current_temp >= desired_temp){
heating = false;
}
if (cooling and current_temp <= desired_temp){
cooling = false;
}
}
};

bool isWellFormedThermostatString(string commands){
Thermostat thermos(commands);
return thermos.valid_command;
}

int temperature(string commands){
Thermostat thermos(commands);
if (thermos.valid_command){
return thermos.current_temp;
}
else return -1;
}

int setting(string commands){
Thermostat thermos(commands);
if (thermos.valid_command and thermos.user_setting){
return thermos.desired_temp;
}
else if(thermos.valid_command){
return 0;
}
else return -1;
}

bool isHeating(string commands){
Thermostat thermos(commands);
if (thermos.valid_command) //Extra security doesn't hurt :)
return thermos.heating;
else return false;
}

bool isCooling(string commands){
Thermostat thermos(commands);
if (thermos.valid_command)
return thermos.cooling;
else return false;
}
int main(){

string str = "T205h55+5";
cerr<<"\nThe command is valid: "<<boolalpha<<isWellFormedThermostatString(str)<<endl<<endl;;
cerr<<"Current temperature is "<<temperature(str)<<endl<<endl;
cerr<<"User's desired temperature "<<setting(str)<<endl<<endl;
cerr<<"Heating: "<<boolalpha<<isHeating(str)<<endl<<endl;
cerr<<"Cooling: "<<boolalpha<<isCooling(str)<<endl<<endl;
}

最佳答案

您的列表用作queuestack 类的直接成员。 queue 类在您的代码中按值传递。自 Rule of Three被你的 list 类违反了,它会不可避免地导致典型的问题,比如双重删除、访问释放的内存等等。

list 的当前编译器提供的复制构造函数和复制赋值运算符执行 list 对象的浅复制,即相同 list< 的所有拷贝 将引用相同的节点链表。当一个这样的实例被破坏时,它会释放列表。之后,其他拷贝将指向已释放的内存。

如果您真的想按值传递这些类,您必须遵循三规则(或五规则)。您必须为您的 list 类正确实现复制构造函数和复制赋值运算符。

另一种解决方案是避免按值传递这些对象。如果您决定采用这种方式,请将复制构造函数和复制赋值运算符定义为“已删除”。这将确保您永远不会无意中对这些对象进行浅拷贝。

关于c++ - 'delete' 在 clang 中完美编译时在 g++ 中抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51395051/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com