首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“删除”在g++中抛出一个错误,同时在clang中完美地编译

“删除”在g++中抛出一个错误,同时在clang中完美地编译
EN

Stack Overflow用户
提问于 2018-07-18 06:34:31
回答 1查看 83关注 0票数 0

因此,我实现了一个标准链接列表,它编译并运行在clang中。然而,g++抛出了许多错误,在删除了常见的内存泄漏之后,有一个错误没有书/文档/教程能够帮助-

代码语言:javascript
复制
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;
    }
}

};

现在,它自己工作得很好。使用它实现的堆栈和队列工作得很好。但是,当析构函数试图调用它时,在某一点上会发生这样的情况-

代码语言:javascript
复制
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函数在同一个程序中多次完美地工作,但是对于一个特定的实例,失败。

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

编辑:这是一个使用分流-场的RPN解析的实现,下面是完整的代码-

代码语言:javascript
复制
    #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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-18 06:58:53

您的列表用作queuestack类的直接成员。类queue是通过代码中的值传递的。由于Rule of Three被您的list类违反了,所以它不可避免地会导致典型的问题,例如双重删除、访问已释放内存等等。

list的当前编译器提供的复制构造函数和复制赋值操作符执行对list对象的浅复制,即相同list的所有副本都将引用相同的链接节点列表。当一个这样的实例被销毁时,它会释放列表。在此之后,其他副本将被保留,指向已释放的内存。

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

另一种解决方案是避免按值传递这些对象。如果您决定这样做,请将复制构造函数和复制赋值操作符定义为“删除”。这将确保您不会不经意地复制这些对象。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51395051

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档