Jack Walsh
Jack Walsh

Reputation: 582

C++: Class object referencing in reassignment rather than copying

I have the following code where a waitline object is created to keep track of the people in line in the form of nodes. The enterLine() function adds a person to the line and points the node before them to their own node. exitLine() removes the first person in the line.

#include <iostream>
#include <string>
using namespace std;
struct node {
    string val;
    node *next;  // this will be the pointer to the person behind this person
};
class waitline {
public:
    waitline() {};
    void enterLine(string x);
    string exitLine();
    int size() { return len; };
    bool isEmpty() {
        if (len == 0) return true; else return false;
    };
    void printLine();
private:
    node * front = NULL, *rear = NULL;
    int len = 0;
};
void waitline::enterLine(string x) {
    if (len == 0) {
        front = new node;
        rear = front;
        front->val = x;
        front->next = NULL;
        len++;
    }
    else {
        rear->next = new node; // rear is the last person in line
        rear = rear->next;  //reset rear to the new node.
        rear->val = x;
        rear->next = NULL;
        len++;
    }

};
string waitline::exitLine() {
    string s;
    if (len == 0) {  // no one in line
        cout << "error-no one in line\n";
        return "";

    }
    else {
        s = front->val;
        front = front->next;
        len--;
        return s;
    }
};
void waitline::printLine() {
    node *temp;
    cout << "FRONT OF LINE\n";
    temp = front;
    while (temp != NULL) {
        cout << temp->val << endl;
        temp = temp->next;
    }
};
int main() {
    waitline w, w2;
    w.enterLine("Joe");
    w.enterLine("Mary");
    w.enterLine("Mikey");
    w2 = w;
    cout << "waiting line w2 is\n";
    w.printLine();
    cout << w.exitLine() << " was served\n";
    w2.enterLine("Susie");
    w.enterLine("Juan");
    w.enterLine("Nguyen");
    cout << w.exitLine() << " was served\n";
    w.printLine();
    cout << w.size() << endl;
    w2.printLine();
    return 0;
}

I expect w2 to only hold the first 3 values (Joe, Mary, and Mikey) as well as Susie, who was explicitly added to w2. When printing w2, however, it gives the output I expect from printLine(w).

Upvotes: 0

Views: 87

Answers (2)

Joseph Larson
Joseph Larson

Reputation: 9068

I want to state erenon's answer a little differently. The problem is this line of code:

w2 = w;

What this does is copy the structure of w into w2. That is, w2.front, w2.rear, and w2.length are copied. The data they point to is not.

In other words, w2.front points to the exact same node as w.front, not a copy of it. So if you modify w2.front->next, you're also at the same time modifying w.front->next, as it's the exact same space in memory.

This is almost certainly not what you want.

If you are going to do w2 = w, then you need to implement a copy operator. You can google for examples of how to write that. But basically what you would do is iterate over the list of nodes, creating a duplicate list, so that neither waitline actually points to the same list of node objects.

Assuming that's what you want -- a distinct NEW LINE, but based on the same strings as the original line, so that changes to one do not affect the other.

I wouldn't do it that way, though. I'd write another method in waitline:

void copyFrom(waitline &orig) {
    for (node *ptr = orig.front; ptr != NULL; ptr = ptr->next) {
        enterLine(ptr->val);
    }
}

Then instead of the copy operation, I would do:

w2.copyFrom(w);

That's almost the same thing as writing a copy operator, but as you're new to this, you don't need to learn copy operator semantics while also learning about pointers.

Upvotes: 0

erenon
erenon

Reputation: 19128

w2 = w does a shallow copy: it copies the pointers, but not the pointed to objects. Therefore, the changes to those pointed objects made via w can be observed via w as well. You need to do a deep copy, e.g: by implementing operator= properly.

The rule of 3/5/0 gives a good explanation on the required members a resource handling object needs to implement.

Otherwise, as the other commenters point out: there are several memory management issues in the code. Unless this is some sort of homework, or a deliberate attempt to learn how pointers work, it'd more efficient to use standard containers, e.g: std::vector, std::dequeue or std::list.

Upvotes: 3

Related Questions