-2

I've been having problems with a segmentation fault that is driving me crazy. Basically I have a class Expression that contains an Expression_Tree. I'm trying to set my variable current_expression equal to a new expression object from an infix string.

Try to set variable to an expression:

try{
    current_expression_ = make_expression(infix); //Segmentation fault here.
}catch(Expression_Error ee){
    cerr << ee.what() << endl;
} 

make_expression takes an infix string, generates a postfix, then generates a Expression_Tree, creates an Expression object with the expression tree and returns it.

Expression make_expression(const string& infix)
{
    string postfix = make_postfix(infix);
    cout << "Made postfix" << endl;
    Expression_Tree* et= make_expression_tree(postfix);
    cout << "Made Expression_Tree" << endl;
    cout << "Returning Expression" << endl;
    return Expression{et};
   }
}

My copy assign operator and swap functions looks like this:

Expression Expression::operator=(const Expression& e) &{
  cout << "In copy assign operator" << endl;
  Expression{e}.swap(*this);
  cout << "Swapped Expression and this" << endl;
  return *this;
}
void Expression::swap(Expression& rhs){
  cout << "In swap function" << endl;
    std::swap(tree, rhs.tree);
}

And my Expression destructor looks like this:

Expression::~Expression(){
  cout << "In Expression destructor" << endl;
  delete tree;
}

Copy constructor

Expression::Expression(Expression_Tree* input_tree)
  :tree(input_tree){}

Output when running the program:

>> u
x=1+1
Made postfix
Made Expression_Tree
Returning Expression
In copy assign operator
In swap function
In Expression destructor
Swapped Expression and this
In Expression destructor
In Expression destructor
Segmentation fault

It seems like the tree is trying to be destroyed two times, so when the destructor gets called the second time it's allready deleated and gives an segmentation fault. Any help in pointing out the problem or any advice is appriciated!

okarlsson
  • 286
  • 1
  • 4
  • 14
  • 2
    Your `make_expression` returns `et`, which is `Expression_Tree*`. How does `Expression_Tree*` become `Expression`? You have a conversion constructor? Also, how is copy constructor of `Expresion` implemented? It's copy constructor that's responsible for copying return values, not assignment operator. – AnT stands with Russia Oct 18 '15 at 21:47
  • 2
    `operator=` returning by value is a huge blunder – M.M Oct 18 '15 at 21:50
  • (In case anyone is wondering about `&` after the assignment operator signature) That feature was added in C++11 and some recommend using it on assignment operators. [Further reading](http://stackoverflow.com/questions/12306226/what-does-an-ampersand-after-this-assignment-operator-mean) – M.M Oct 18 '15 at 21:51
  • Sorry, some code went missing (It's in middle of the night here, not the best focus..). I edited the code so it should be correct. – okarlsson Oct 18 '15 at 21:51
  • also: @Oskar: Please, pretty please, use RAII, don't use raw pointers for ownership like in `make_expression_tree` – Chris Beck Oct 18 '15 at 21:51
  • I got this operator= functions that return this* from my university lecturer. Do you have any other recommendations as to how I should implement it? @M.M – okarlsson Oct 18 '15 at 21:53
  • @M.M.: thanks I missed that, deleting the comment – Chris Beck Oct 18 '15 at 21:54
  • @Oskar see [this thread](http://stackoverflow.com/questions/4421706/operator-overloading) for good advice about operator overloading. The return type should be `Expression &` . – M.M Oct 18 '15 at 21:54
  • @Oskar Your professor needs a C++ teacher. – PaulMcKenzie Oct 18 '15 at 21:57
  • Thank you for the advice @M.M and I'll keep that that in mind @PaulMcKenzie! – okarlsson Oct 18 '15 at 22:00
  • Any thoughts on what might be causing the segmentation fault? – okarlsson Oct 18 '15 at 22:03
  • @Oskar Unless you didn't write down exactly what the teacher wrote, you should be returning a reference, not an object. Otherwise, if your copy constructor is correct, and your destructor is ok, and `tree` is the *only* data member, then the code should work. However, if there is a problem with `tree` itself, then you need to see if `tree` is causing the problem. It seems that `tree` is non-trivial (is not a POD type), so it needs to be copyable also for this to work. – PaulMcKenzie Oct 18 '15 at 22:03
  • @Oskar - Also `Expression_Tree* et= make_expression_tree(postfix);` As the other comment suggested, this is not a good idea. How about returning an Expression_Tree object and not a pointer? – PaulMcKenzie Oct 18 '15 at 22:07
  • I tried to remove the variable current_expression_ and just run the make_expression(infix) function and this does not give me an segmenatation fault. Shouldn't that mean that the problem is in the operator= or the destructor? @PaulMcKenzie – okarlsson Oct 18 '15 at 22:08
  • @Oskar Your assignment operator uses the copy / swap idiom. This will always work correctly *if* you have a properly working copy constructor and destructor. The copy and swap relies on those two other functions to be flawless. Also, you didn't post *all* of the data members of `Expression` -- if you have other members besides `tree`, then you need to swap those also, not just `tree` (I'm talking about the `swap()` function itself. Other than that, you really should have unit tested your class using simple functions *before* embarking on using it in a larger program. – PaulMcKenzie Oct 18 '15 at 22:13
  • @PaulMcKenzie tree is the only data member in expression. It seems like the tree pointer is pointing somewhere in the memory that it is not supposed to. I tried to do some outputs of tree: `Expression::~Expression(){ cout << "In Expression destructor" << endl; if(tree != nullptr){ cout << tree << endl; cout << tree->str() << endl; delete tree; } }` This gives me the output: ` In Expression destructor 0xeecc50 Segmentation fault ` – okarlsson Oct 18 '15 at 22:29
  • @Oskar: One more time: where's your copy constructor? Your code relies critically on properly implemented copy constructor. You haven't shown your copy constructor yet. Did you even write one? This are the primary "thoughts on what might be causing the segmentation fault" and they have been posted here in the very first comment. – AnT stands with Russia Oct 18 '15 at 22:46
  • @Oskar: What you added is a *conversion* constructor. *Copy* constructor should have `Expression::Expression(const Expression &)` signature. Did you write a copy constructor? If not, then this is your problem. Read about C++ Rule of Three on the Net. – AnT stands with Russia Oct 19 '15 at 03:15
  • @Oskar That is not a copy constructor. You need to write one that does the real copying of the object to the newly created object. The copy-swap idiom relies on this function to be implemented and working properly. I'm surprised your code even left this out, as it can't work without it. In other words, this is where you actually deep-copy the `tree` object from the passed-in reference to the newly created object (no swapping -- actually you need to copy `tree` to the new object). Once you write that function, then and only then will the rest of your code work. – PaulMcKenzie Oct 19 '15 at 03:56

1 Answers1

0

The problem was a missing copy constructor as pointed out by AnT and PaulMcKenzie:

What you added is a conversion constructor. Copy constructor should have Expression::Expression(const Expression &) signature. Did you write a copy constructor? If not, then this is your problem. Read about C++ Rule of Three on the Net.

okarlsson
  • 286
  • 1
  • 4
  • 14