0

I have to create a function which overloads the = operator so that when you put object1 = object2; it'll copy over all the values inside object2 into object1.

My class looks like:

class foo {
  private:
    int max;
    int *val;
    size_t *listofVal;
}

And my overload function is declared as:

foo& foo::operator=(const foo& matrix);

foo::foo(std::istream& s);  //constructor

how would I do this?

iammilind
  • 68,093
  • 33
  • 169
  • 336
SNpn
  • 2,157
  • 8
  • 36
  • 53

3 Answers3

5

The best way to do this is by using Copy and Swap Idiom.
Also, note that if you feel the need of overloading the copy assignment operator then you also probably need to overload copy constructor as well as the destructor for your class.

Do have a look at Rule of Three.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Note that Copy and Swap will give you the strong exception safety guarantee, which you may not need. Use CAS by default, but consider implementing an assignment operator with only the weak guarantee if you run into (profiled) performance issues. – Mankarse Aug 30 '11 at 11:14
  • @Mankarse: Why do you think that copy and swap will be non optimal? – Martin York Aug 30 '11 at 13:40
  • @Martin, because copy and swap means that each primitive in the object has to be copied into a temporary and then assigned from that temporary into the assignee. This could be slow for a large object that do not own many external resources. You also lose opportunities to reuse memory that the assignee has already allocated. I think that most programs would not be significantly slowed down by these things, but it is worth knowing that there _are_ correct alternatives to Copy and Swap. – Mankarse Aug 30 '11 at 13:56
  • @Mankarse: You need to do all the work anyway even if you do not use CAS. So it makes no difference. Write it out by hand there is no extra allocations it is just done into a box rather that into a list of local temporaries. – Martin York Aug 30 '11 at 14:00
  • @Martin - struct With { char a[1000]; With& operator=(With o) {swap(o);} }; struct Without { char a[1000]; Without& operator=(Without const& o){a = o.a;} }; In the first example there is a copy into o, and then the cost of a swap. In the second example there is just a single assignment. If the cost of copying the data members significantly outweighs the cost of copying the owned resources, then copy and swap will be significantly slower. – Mankarse Aug 30 '11 at 14:09
  • @Mankarse: Not a valid comparison. 1) `Without` will not compile (you do actually need to copy it). 2) There are no resource here to manage. 3) If these were owned pointers you still need to copy them. Come up with a real example were there is less work in Without. – Martin York Aug 30 '11 at 14:19
  • @Martin let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3001/discussion-between-mankarse-and-martin) – Mankarse Aug 30 '11 at 14:28
1

Simply copying all the values is the default behaviour of the compiler supplied copy contructor. This is known as a "shallow-copy".

More elaborate behaviour is achieved by implementing your own constructor so that the objects (here values) pointed to by your reference are created anew in the copy.

foo::foo(std::istream& s) {
    max = s.max;
    val = new int;
    *val = s->val;
    listofVal = new size_t;
    *listofVal = s->listofVal;
}

would be one way of achieving that which is known as a "deep copy".

But as one of your members is called listofVal I rather feel you are doing something other than storing a single value at the memory address it points, in which case you should be holing a counter to the number of elements contained therein, which I will henceforth assume to be the field you call max. To copy the whole list, your copy constructor would then need to be:

foo::foo(std::istream& s) {
    max = s.max;
    val = new int;
    *val = s->val;
    listofVal = new size_t[max];
    for (int i = 0; i < max; ++i)
        listofVal[i] = s->listofVal[i];
}

Ravi, yes, the copy constructor is a proof of construct and despite breaking the "Rule Of Three" can be implemented before the other two. Here is the assignment operator.

foo& foo::operator=(const foo& matrix) {
    if (this != matrix) {
        max = matrix.max;
        val = new int;
        *val = matrix->val;
        listofVal = new size_t[max];
        for (int i = 0; i < max; ++i)
            listofVal[i] = matrix->listofVal[i];
    }
}

would be suitabe for object1 = object2; assignment. I tend towards the copy constructor approach.

The methods need to be members to access the private data so your class should be like

class foo {
    ///...///As before
    foo &operator=(const foo& matrix);
};

Of course it needs a destructor but as it was not explicitly requested I didn't want to answer what wasn't asked.

Following on from the link to the Copy and Swap idiom, when the LHS may already contain data, for robust assignment you might consider:

foo& foo::operator=(const foo& matrix) {
    if (this != matrix) {
        val = new int;
        *val = matrix->val;
        size_t* newArray = new size_t[max];
        int newMax = matrix.max;
        std::copy(matrix.listofVal, matrix.listofVal + max, newArray);
        if (listofVal) delete listofVal;
        listofVal = newArray;
        max = newMax;
    }
}

I would add that assigning local objects on the heap can cause memory leaks (if the method breaks before they are assigned to an object responsible for their deletion), but that is just a whole nother layer of parannoia when we have enough to do preserving class integrity.

John
  • 6,433
  • 7
  • 47
  • 82
  • 1
    I think you meant to define `foo& foo::operator=(const foo& matrix)` – bluefalcon Aug 30 '11 at 11:02
  • @John are we allowed to do this even if they are private? – SNpn Aug 30 '11 at 11:06
  • Additionally you must take care of pointers if memory is allocated for them in foo ctor. If it is so you must include checking of self-assignment to avoid memory corruption, otherwise memory will be released twice. – Riga Aug 30 '11 at 11:09
  • @SNpn, yes, you have indicated that they are members of your class foo. In that case you would need to declare them inside the class declaration/definition in the header. – John Aug 30 '11 at 11:12
  • Of course it needs a destructor but it seemed like to much work to write that as well when it was not explicitly requested. – John Aug 30 '11 at 11:20
-1

Googling for "C++ Assignment Operator" gives you this useful site ;-)

Tim Meyer
  • 12,210
  • 8
  • 64
  • 97
  • I think it is not useful an answer like that, you can find a lot of "bad teachers" in the web. That's why people post questions on this web site – Alessandro Teruzzi Aug 30 '11 at 11:47
  • I think researching this topic on one's own (not necessarily on the internet, but also in books) would have been possible, that's why I just posted a link. I guess I will refrain from doing so in the future. – Tim Meyer Aug 30 '11 at 14:46