Search code examples
c++copy-assignment

Understanding and using a copy assignment constructor


I'm trying to understand how the copy assignment constructor works in c++. I've only worked with java so i'm really out of my waters here. I've read and seen that it's a good practice to return a reference but i don't get how i should do that. I wrote this small program to test the concept:

main.cpp:

#include <iostream>
#include "test.h"

using namespace std;

int main() {
    Test t1,t2;
    t1.setAge(10);
    t1.setId('a');
    t2.setAge(20);
    t2.setId('b');

    cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";

    t2 = t1; // calls assignment operator, same as t2.operator=(t1)

    cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";

    Test t3 = t1; // copy constr, same as Test t3(t1)

    cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";

    return 1;
}

test.h:

class Test {
    int age;
    char id;

    public:
        Test(){};
        Test(const Test& t); // copy
        Test& operator=(const Test& obj); // copy assign
        ~Test();
        void setAge(int a);
        void setId(char i);
        int getAge() const {return age;};
        char getID() const {return id;};
};

test.cpp:

#include "test.h"

void Test::setAge(int a) {
    age = a;
}

void Test::setId(char i) {
    id = i;
}

Test::Test(const Test& t) {
    age = t.getAge();
    id = t.getID();
}

Test& Test::operator=(const Test& t) {

}

Test::~Test() {};

I can't seem to understand what i should be putting inside operator=(). I've seen people returning *this but that from what i read is just a reference to the object itself (on the left of the =), right? I then thought about returning a copy of the const Test& t object but then there would be no point to using this constructor right? What do i return and why?


Solution

  • We return a reference from the assignment operator so we can do some cool tricks like @SomeWittyUsername shows.

    The object we want to return a reference to is the one who the operator is being called on, or this. So--like you've heard--you'll want to return *this.

    So your assignment operator will probably look like:

    Test& Test::operator=(const Test& t) {
        age = t.getAge();
        id = t.getID();
        return *this;
    }
    

    You may note that this looks strikingly similar to your copy-constructor. In more complicated classes, the assignment operator will do all the work of the copy-constructor, but in addition it'll have to safely remove any values the class was already storing.

    Since this is a pretty simple class, we have nothing we need to safely remove. We can just re-assign both of the members. So this will be almost exactly the same as the copy-constructor.

    Which means that we can actually simplify your constructor to just use the operator!

    Test::Test(const Test& t) {
        *this = t;
    }
    

    Again, while this works for your simple class, in production code with more complicated classes, we'll usually want to use initialization lists for our constructors (read here for more):

    Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }