-1

I set up a "parent class pointer" vector with size 2 to store its "derived class" address but seem like this vector only stores final address no matter how many address i added, so its cause "Access violation reading" problem. By the way i used composite pattern.

I've tried many ways, i've used vector, 2d pointer (Ex: int**).

class Node{
    public:
        virtual double evaluate();
};
class NumNode: public Node{
   private:
        double number;
    public:
        double evaluate();
        NumNode(int);
};
class OpNode: public Node{
    private:
        char operation;
        vector<Node*> branch;
    public:
        double evaluate();
        void addLeft(NumNode);
        void addRight(NumNode);
        OpNode(char);
};

double OpNode::evaluate(){
    if(this->operation == '+')
        return this->branch[0]->evaluate() + this->branch[1]- 
            >evaluate();**Exception thrown at 0x008C6097 in 
                          Project_Testing.exe: 0xC0000005: Access 
                          violation reading location 0xCCCCCCCC.**

return 0; 
}

void OpNode::addLeft(NumNode other){this->branch[0] = &other;}
void OpNode::addRight(NumNode other){this->branch[1] = &other;}

int main(){
    OpNode n('+');
    n.addLeft(NumNode(2));
    n.addRight(NumNode(3));
    cout << n.evaluate() << endl;
}

As you look into the main funciton, i've add two diffrent NumNode. But when i started debugging. branch[0] 0x006ff620 {...} Node * branch[1] 0x006ff620 {...} Node *. They had the same address!

Nguyen Bot
  • 13
  • 5
  • 1
    Your `addLeft` and `addRight` take the address of the stack parameter `other`. Since the stack looks exactly same for both calls, you see exactly the same address. Either pass in a real pointer that can be stored directly, or (in your methods) allocate a copy (with `new NumNode(other)`) and store *that* address. – Botje Aug 26 '19 at 11:35
  • If you continue down the path of storing copies, it is probably best to add a `Node::clone` method you can call to get an instance of the proper subclass. – Botje Aug 26 '19 at 11:36
  • In `this->branch[0] = &other;` expression you store pointers to temporary objects (`other`). You cannot refer to that addresses anymore afterwards. – vahancho Aug 26 '19 at 11:37
  • Actually, just start using `shared_ptr` and you get reference-counted op trees for free. – Botje Aug 26 '19 at 11:46
  • you don't even need to use dynamic memory if you are using objects in main function only. You can just create variables there and pass by reference. – Bineesh Aug 26 '19 at 11:55

2 Answers2

0

You issue is here:

void OpNode::addLeft(NumNode other){this->branch[0] = &other;}
void OpNode::addRight(NumNode other){this->branch[1] = &other;}

As mentioned in comment:

Your addLeft and addRight take the address of the stack parameter other. Since the stack looks exactly same for both calls, you see exactly the same address. Either pass in a real pointer that can be stored directly, or (in your methods) allocate a copy (with new NumNode(other)) and store that address.

Another way around it you will probably wan't for nodes is using std::shared_ptr So your nord list becomes:

vector<shared_ptr<Node> > branch;

and then:

void OpNode::addLeft(const shared_ptr<NumNode> >& other){this->branch[0] = other;}
darune
  • 10,480
  • 2
  • 24
  • 62
0

You are taking pointer to temporary object. When this objects lifetime ends referencing it is an Undefined Behavior, what in this case ends with a crash.

Create this objects on heap to extend lifetime of required objects.

For example:

class Node{
    public:
        virtual ~Node() {}
        virtual double evaluate();
};

class NumNode: public Node {
    private:
        double number;
    public:
        double evaluate();
        NumNode(int);
};

class BinaryOpNode: public Node{
    private:
        std::unique_ptr<Node> left;
        std::unique_ptr<Node> right;
    public:
        BinaryOpNode(std::unique_ptr<Node> a, std::unique_ptr<Node> b)
           : left{std::move(a)}
           , right{std::move(b)}
        {
        }

        double evaluate() {
           return binaryOperator(left->evaluate(), right->evaluate());
        }
        virtual double binaryOperator(double a, double b) = 0;
};

class AddOpNode : public BinaryOpNode {
public:
    using BinaryOpNode::BinaryOpNode;

    double binaryOperator(double a, double b) { return a + b; }
};

int main(){
    AddOpNode n {
        std::make_unique<NumNode>(2), 
        std::make_unique<NumNode>(3)
    };

    cout << n.evaluate() << endl;

    return 0;
}
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Thanks for your help, but i just forgot to tell you that this is an exercises you have to follow the main function. – Nguyen Bot Aug 26 '19 at 14:27