1

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;
}
4pie0
  • 29,204
  • 9
  • 82
  • 118
awiebe
  • 3,758
  • 4
  • 22
  • 33
  • 2
    http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – chris Nov 03 '13 at 00:10
  • Using a reference as a struct/class member is uncommon and darn tricky. You have to be absolutely sure the lifetime of the referenced thing is longer than the lifetime of the struct object. – aschepler Nov 03 '13 at 00:16

2 Answers2

3
//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.

Community
  • 1
  • 1
4pie0
  • 29,204
  • 9
  • 82
  • 118
  • So a reference ceases existing when I exit scope, but a pointer remains in the heap. Leaving scope includes jumping in one level, even if I use the syntax addTerm(Term& t). Therefore the only way to build a list on the heap is to pass a bunch of pointers around, as I would expect? – awiebe Nov 03 '13 at 00:19
  • a pointer is stored on stack to be specific, but the object pointed to is stored on heap.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, I added this to anwer – 4pie0 Nov 03 '13 at 00:26
  • That is a good point. Yes I mean the pointer is an automatic, but leaving scope does not free what it points to, where as leaving scope will delete a reference, even if it is a call instead of a return. Is that correct? – awiebe Nov 03 '13 at 00:30
  • yes, this is correct: this doesn't free an object allocated on a free store (this will delete object however if it was built on stack, it is possible too) – 4pie0 Nov 03 '13 at 00:34
1

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

dnk
  • 661
  • 4
  • 5