I am creating a binary tree representation of a mathematical expression for performing differentaiton and integration on it.
I am trying to overload the + operator for my Symbol class. It works fine for:
Symbol("x") + Symbol(2.3);
The issue arises when I want to support expressions like:
Symbol("x") + 2.3;
where a Symbol object is added to a double(floating point).
I have implemented two approaches: Approach 1 (Works but has Code Duplication)
Symbol operator+(double other){
Symbol *temp = new Symbol(other);
if (this->is_constant) {
double value = this->value + temp->value;
Symbol temp2(value);
return temp2;
}
Symbol temp2;
temp2.op = '+';
temp2.left = this;
temp2.right = temp;
return temp2;
}
This works, but the logic for adding two Symbol objects is almost identical to this function, leading to redundant code.
Approach 2 (Causes Segmentation Fault) To reduce redundancy, I tried:
Symbol operator+(double other){
Symbol *temp = new Symbol(other);
return *this + *temp; // Causes segmentation fault when try to access other later
}
Symbol("x") + 2.3
However, this leads to a segmentation fault when try to access this *temp (2.3) object in main fucntion because temp is dynamically allocated but temp pass copy of that object and its scope lost after this function ends.
So, i main motive of posting this question is to know is there any better way to implemnt this?
Here is complete code for reference:
#include <iostream>
#include <memory>
class Symbol{
public:
std::string name = "";
bool is_constant = false;
bool is_expression = false;
char op;
double value = 0.0;
Symbol* left = nullptr;
Symbol* right = nullptr;
Symbol() {is_expression = true;}
Symbol(std::string name) {this->name = name;}
Symbol(double value) {this->value = value; this->is_constant = true;}
~Symbol() {};
Symbol operator+(Symbol other){
if(this->is_constant & other.is_constant){
double value = this->value + other.value;
Symbol temp(value);
return temp;
}
Symbol temp;
temp.op = '+';
temp.left = this;
temp.right = &other;
return temp;
}
Symbol operator+(double other){
Symbol *temp = new Symbol(other);
if(this->is_constant){
double value = this->value + temp->value;
Symbol temp2(value);
return temp2;
}
Symbol temp2;
temp2.op = '+';
temp2.left = this;
temp2.right = temp;
return temp2;
// // uncomment below line and comment above function code and this will give segmentation fault
// return *this + *(new Symbol(other));
}
void print(){
if(this->is_expression){
std::cout << "( ";
this->left->print();
std::cout << this->op << " ";
this->right->print();
std::cout << ") ";
return;
}
if(this->is_constant){
std::cout << this->value << " ";
return;
}
std::cout << this->name << " ";
}
};
/*
z
/ \
x (2.3)
*/
int main(){
Symbol x("x");
Symbol z = x + 2.3;
z.print();
}
temp.right = &other;) looks bad. Yor intention is fortemp.rightto point toother, butothergoes out of scope in the very next line! That is, as soon as thereturnstatement in line 30 is hit,temp.rightpoints to invalid data. That could be a cause of the Segmentation Fault that you're seeing.Symbol operator+(double other)method? The other method (Symbol operator+(Symbol other)) should handle a double just fine. If you're wondering why, it's because you already defined a constructor that takes adouble. So if you pass adoubleintoSymbol operator+(Symbol other), theSymbol(double value)constructor will convert thedoubleto aSymbol, doing the conversion for you.Symbolon the heap but then end up not using and forgetting the pointer) and dangling pointers (where you save an address of a temporary, then that temporary is destroyed). Before worrying about style, you need to reconsider your design, paying careful attention to ownership - who owns what, when is memory allocated and destroyed, how do you ensure that pointers don't outlive the objects they point to.Symbol('x') + 2.3Instead of forcing explicit conversions:Symbol('x') + Symbol(2.3)This way, we can write functions naturally, e.g.,f(x) = x + 2.3Symbol('x') + 2.3is better. But you don't need to define aSymbol operator+(double other)method to support it. If you have trouble believing that, try commenting out theSymbol operator+(double other)method and see if the lineSymbol('x') + 2.3still compiles.