为什么我的代码出现分段错误

时间:2019-05-30 20:34:32

标签: c++ oop segmentation-fault

在我的生命中,我根本无法理解为什么该程序会出现细分错误。问题在于,它在向量容器中检索对象时,会使用菜单类中的get_command()函数,并且出于某种原因,在逐行测试主函数后,这会导致分段错误:

menu->get_command()->execute();

我尝试更改语法以创建一个新的命令对象,该对象存储从get_command()返回的对象,并将索引更改为0到-1之间,但仍然无法解决该错误。我花了至少几个小时试图找出原因,但似乎找不到解决方案。

class Base {
public:
    /* Constructors */
    Base() { };

    /* Pure Virtual Functions */
    virtual double evaluate() = 0;
    virtual std::string stringify() = 0;
};

class op : public Base
{
public:
    op() { };
    op(double op1) { operand = op1; }

    double evaluate() { return operand; }

    string stringify() {
        string value = to_string(operand);
        return value;
    }
private:
    double operand;
};

class Command {
protected:
    Base* root;

public:
    Command() { this->root = nullptr; }
    double execute() { return root->evaluate(); }
    std::string stringify() { return root->stringify(); }
    Base* get_root() { return root; }
};



class Menu {
private:
    int history_index; // Indexes which command was last executed, accounting for undo and redo functions
    std::vector<Command*> history; // Holds all the commands that have been executed until now

public:
    Menu() {
        // Constructor which initializes the internal members
        history_index = -1;
    }

    std::string execute() {
        // Returns the string converted evaluation of the current command
        return to_string(history[history_index - 1]->execute());
    }

    std::string stringify() {
        // Returns the stringified version of the current command
        return history[history_index]->stringify();
    }

    bool initialized() {
        // Returns if the history has an InitialCommand, which is necessary to start the calculation
        if (history[history_index] != nullptr)
            return true;
        else
            return false;
    }

    void add_command(Command* cmd) {
        // Adds a command to the history (does not execute it), this may require removal of some other commands depending on where history_index is
        history.push_back(cmd);
        history_index++;
    }

    Command* get_command() {
        // Returns the command that the history_index is currently referring to
        return history[history_index];
    }

    void undo() {
        // Move back one command (does not execute it) if there is a command to undo
        history_index--;
    }

    void redo() {
        // Moves forward one command (does not execute it) if there is a command to redo
        history_index++;
    }
};


class InitialCommand : public Command {
protected:
    Base* root;

public:
    InitialCommand(Base* b) { this->root = b; }
    double execute() { return root->evaluate(); }
    std::string stringify() { return root->stringify(); }
    Base* get_root() { return root; }
};


void main()
{
    Menu* menu = new Menu();
    InitialCommand* temp = new InitialCommand(new op(7));
    menu->add_command(temp);
    EXPECT_EQ(menu->get_command()->execute(), 7);

    system("PAUSE");

}

2 个答案:

答案 0 :(得分:0)

您没有正确执行继承权限,因为您在CommandInitialCommand之间复制了导致错误的字段。

两个命令类都有一个Base *root成员和非虚拟execute方法。构造新的InitialCommand对象时,InitialCommand::root对象指向为其创建的op,而Command::root由于默认的构造函数而保持NULL的位置。 Command。然后,当您调用menu->get_command()时,它将调用Command::execute,因为execute是非虚拟的,而menuCommand *Command::execute随后将取消引用NULL root,从而导致您的细分错误。

Base *root中删除InitialCommand成员,并将参数传递给Command中的构造函数。您可能想使某些方法像execute是虚拟的。

答案 1 :(得分:0)

问题是您的b8eead8ba4ff375911af6 c2452680eb7731e4d36ca da2e113ca4768f5f34730 95b98d42a6e567ed56fc2 716c4f84a855f48bee55c 6a7223a74269f925cfd9e---I need this one e945bcfabf3fbafc85084---latest_sha 159df375376ded565bec0 d725350982626f46a8b80 56a4b6ca91d93acc8d751 de584608616b1ed99a554 3cfc15339a98bb286d5baa 6ae834bf36c90fbd81854 fa9bdebd0f814f04ee05ba cc44c4d9ff14314c1255da 5a6145586a8fdcaa2da659 bfea8cfe121d24a0ff1525 Command都具有InitialCommand变量。 root将根据您的构造函数设置InitialCommand* temp = new InitialCommand(new op(7));。因此InitialCommand::root仍未初始化。然后Command::root持有Menu,因此std::vector<Command*>被隐式转换为InitialCommand*。 最终,调用Command*的确会调用Command::execute,因为该方法不是虚拟的。因此,使用未初始化的Command:execute->段。错误。

请不要使用Command::root。使用智能指针-new应该是管理动态内存的默认方式。

也就是说,您的代码似乎太像Java / C#。这是C ++,请尽可能使用值语义。没有理由使用std::unique_ptrMenu* menu = new Menu();比较简单,在您的情况下也一样。这是我要编写的代码

Menu menu;

它使用的move semantics过去不是一个初学者的概念,但是它是现代C ++不可或缺的一部分,因此每个C ++程序员都必须尽快学习它。