awiebe
awiebe

Reputation: 3846

Unusual C++ behaviour when calling constructor

In an effort to become a more competent C++ programmer I'm experimenting w/ using references. In the past I have usually used pointers when referring to objects, as you would for example in Objective-C.

So I've been programming a Polynomial class that stores a list of Term objects

(TermNode* termHead,termTail)

But when I try to add a term to the list using the first implementation listed, calling the constructor on Term in add term, overwrites the Term& reference in the previously created Term node, as if it used the this pointer from the previous invocation of the constructor.

What is technically wrong about the first implementation listed, that causes it to behave so abnormally? It just works when I use pointers and new even though I do not change the structure of TermNode.

struct TermNode {
    Term& value;
    TermNode* next;
};

Term::Term(int coefficient,int firstTermDegrees,int secondTermDegrees) {
        this->coefficient = coefficient;
        this->xDegree = firstTermDegrees;
        this->yDegree = secondTermDegrees;
    }

//Doesn't work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree) {
    Term term(coefficient,xDegree,yDegree);
    addTerm(term);
}

void Polynomial::addTerm(Term& term) {
    TermNode* t = new TermNode{term,nullptr};
    if(isEmpty())
    {
        termHead = t;
        termTail = t;
    }
    else
    {
        termTail->next = t;
        termTail = termTail->next;
    }

}

//Does work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree) {
    Term* term = new Term(coefficient,xDegree,yDegree);
    addTerm(term);
}

void Polynomial::addTerm(Term* term) {
    TermNode* t = new TermNode{*term,nullptr};
    if(isEmpty())
    {
        termHead = t;
        termTail = t;
    }
    else
    {
        termTail->next = t;
        termTail = termTail->next;
    }

}

bool isEmpty() {
return nullptr == termHead;
}

Upvotes: 1

Views: 72

Answers (2)

4pie0
4pie0

Reputation: 29734

//Doesn't work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree)
{
    Term term(coefficient,xDegree,yDegree);//here you created automatic object
    addTerm(term);                         //it will be deleted in next line
}                                    //it is an error to call addTerm(Term& term)

this works

//Does work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree)
{
    Term* term = new Term(coefficient,xDegree,yDegree);
    addTerm(term);
}

because here you created object on a free store. It's life is extended till you call delete on it (side note: call delete somewhere, at this moment you have a memory leak! or use smart pointer), so this works just fine.

void Polynomial::addTerm(Term* term)
{
    TermNode* t = new TermNode{*term,nullptr};
    // ...
}

You can use references but in the way they are supposed to be used. You can't use a reference to temporary when it was actually deleted. You can bind temporary object to const reference however, but because of your struct definition

struct TermNode
{
    Term& value;
    TermNode* next;
};

in constructor you take a reference again, so binding temporary to const reference in this case will again result in segmentation fault.

Upvotes: 3

dnk
dnk

Reputation: 661

In the first implementation you passes a reference to a temporary object which is destroyed at the end of method addTerm.

Upvotes: 1

Related Questions