C++, Proper copy operator overloading - c++

I want to redirect my copy operator to my copy constructor. Where in the latter I implement the proper logic for copying/contructing a new class based on the old avaialble class.
However, how is the proper way to do this? I "think" this one is maybe leaking memory, but I don't know how to do it without passing a pointer:
MyClass& MyClass::operator=(const MyClass& a) {
MyClass* b = new MyClass(a);
return *b;
}
Is this OK? If is not, what would be the proper way? Should I change the body of the method or the prototype?
Thank you.

No, an operator= should set the current object attributes to be the same as the object assigned. Your method assigns a new object on the heap, returns it as a reference (essentially leaking it) and leaves the object the operator was called on completely unchanged.
You should implement a method called, for example, CopyFrom(), which assigns all the object's attributes to match those of the passed in object (deep copying any heap allocated pointers whose lifetime is managed by MyClass) and then call THAT from both your copy constructor and your operator=.
class MyClass
{
public:
MyClass( const MyClass& in )
{
CopyFrom( in );
}
MyClass& operator=( const MyClass& in )
{
CopyFrom( in );
return *this;
}
private:
void CopyFrom( const MyClass& in )
{
... copies in's attributes into self.
}
};

As a rule, a copy assignment operator should never create a copy. Rather, it should copy data into the existing object that it's called on (the left-hand side of the assignment). For example:
class MyClass
{
public:
MyClass & operator = (const MyClass & RHS)
{
// Copy data from RHS into 'this'
m_value = RHS.m_value;
return *this;
}
private:
int m_value;
};
In this case, defining your own copy constructor isn't necessary because the default (compiler-provided) one would work fine. It's just an illustration though.
Unfortunately you can't invoke the copy constructor on the existing object. The copy-swap pattern is an alternative, but it can be less efficient.

Unless you're storing pointers inside of MyClass, the correct copy assignment operator is the default-generated one. If, however you need to implement one, you can write it in terms of your copy-constructor via the copy-swap idiom:
MyClass& MyClass::operator = (MyClass const& a) {
MyClass temp(a); // Call the copy constructor
using std::swap;
swap(temp, *this);
return *this;
}
The reason for the using std::swap is to enable argument-dependent lookup. If you define your own swap function for MyClass, it will be called. Else std::swap will be used as a fallback. (EDIT: You do in fact need to implement a custom swap in this case, or else you will get infinite recursion. std::swap will use the assignment operator, which will call std::swap, which will call the...)
The reason that this idiom is well-liked is because std::swap is a no-throw function. If your copy-constructor were to throw an exception, then your object you're assigning to is still in a valid state.

The "proper way" is to implement the assignment operator like an assignment operator: modify the contents of the object on which the operator is being called and return a reference to it.
Your current implementation will result in a memory leak, AND doesn't do any assignment (which is the main point of the assignment operator).
If you only want to write the assignment code once, and your class doesn't allocate memory in the constructor, you could do this:
MyClass::MyClass(const MyClass& a) {
*this = a;
}
MyClass& MyClass::operator=(const MyClass& a) {
if (&a == this)
return *this;
// Do assignment
return *this;
}
But I wouldn't recommend it.

Your code is totally wrong (sorry)! The assignment operator does
not assign anything, but allocates a pointer to a MyClass object,
creating a memory leak. My advice: avoid pointers or use some
smart pointer (shared_ptr, unique_ptr), but that is just a side note.
Maybe this is helpful:
#include <iostream>
#include <limits>
class X
{
public:
X(std::size_t n)
: m_size(n), m_data(new int[n])
{
std::cout << "Construct" << std::endl;
}
~X()
{
std::cout << "Destruct" << std::endl;
delete [] m_data;
}
// Exception safe assignment.
// Note: I am passing by value to enable copy elision and
// move semantics.
X& operator = (X x) {
std::cout << "Assign" << std::endl;
x.swap(*this);
return *this;
}
void swap(X& x) {
std::swap(m_size, x.m_size);
std::swap(m_data, x.m_data);
}
std::size_t size() const { return m_size; }
private:
std::size_t m_size;
int* m_data;
};
int main()
{
X x(1);
try {
x = X(2);
// To provoke an exception:
std::size_t n = std::numeric_limits<std::size_t>::max();
x = X(n);
}
catch(...) {
std::cout << "Exception" << std::endl;
}
std::cout << "Size: " << x.size() << std::endl;
return 0;
}

If you absolutely want to implement the assignment operator by copy constructor, use the following:
MyClass& MyClass::operator=(const MyClass& o)
{
this->~MyClass(); // destroy current object
new(this) MyClass(o); // use the copy constructor
return *this;
}
I cannot think of any situation in which this would be the best thing to do (other answers describe ways of implementation that are better in some situations).
Maybe (just trying to make things up here) if MyClass contains hundreds of int/float fields, and several dynamically-allocated pointers?
Duplicating them in constructor and assignment operator is too tedious and error-prone
Having a copying function that both constructor and assignment operator call - not ideal, because pointers have to be set to NULL first
The code above - will work with no additional effort!
However, having bare (non-smart) pointers in your class is discouraged. If you have such a class, then you have far worse problems than non-working assignment operator - you have to refactor first, and the problem will go away, together with all other bugs.

Related

How to correctly manage resources with move semantics?

struct foo{
int* i;
foo(): i(new int(42)){}
foo(const foo&) = delete;
foo(foo&&) = default;
~foo(){
std::cout << "destructor: i" << std::endl;
delete(i);
}
};
int main()
{
foo f;
auto sp_f = std::make_shared<foo>(std::move(f));
}
This is bad because it seems that the destructor of f will be called once it moves into the shared_ptr. The shared_ptr will have a deleted pointer and will delete it after it goes out of scope, which means the pointer will be deleted two times.
How do I avoid this problem?
You need to define the move constructor to prevent deletion from the moved-from object:
foo(foo&& f): i(f.i) {
f.i = nullptr;
}
Now when to destructor of the old object is run, it won't delete the i, since deleting a null pointer is a no-op.
You should also define a move assignment operator and delete the copy assignment operator too.
The rule of three is really the rule of five now. If you have a class that can be moved from, you should define the move semantics yourself (plus the copy, destructor, etc).
As to how to do that, to quote cppreference's page on std::move, "... objects that have been moved from are placed in a valid but unspecified state." The unspecified state is typically what the object would look like if it had been default initialized, or what would happen if the objects had swap called on them.
A straightforward way is, as #zenith has answered, is to have the move constructor (or assignment operator) set the original pointer to nullptr. This way the data isn't freed, and the original object is still in a valid state.
Another common idiom is, as mentioned, to use swap. If a class needs its own copy and move semantics, a swap method would be handy as well. The move constructor would delegate initialization to the default constructor, and then call the swap method. In a move assignment operator, just call swap. The object being moved into will get the resources, and the other object's destructor will free the original ones.
It would usually look like this:
struct Foo
{
void* resource; //managed resource
Foo() : resource(nullptr) {} //default construct with NULL resource
Foo(Foo&& rhs) : Foo() //set to default value initially
{
this->swap(rhs); //now this has ownership, rhs has NULL
}
~Foo()
{
delete resource;
}
Foo& operator= (Foo&& rhs)
{
this->swap(rhs); //this has ownership, rhs has previous resource
}
void swap(Foo& rhs) //basic swap operation
{
std::swap(resource, rhs.resource); //thanks #M.M
}
};

calling copy constructor in assignment operator

In an already existing class of a project I am working on I encountered some strange piece of code: The assignment operator calls the copy constructor.
I added some code and now the assignment operator seems to cause trouble.
It is working fine though if I just use the assignment operator generated by the compiler instead. So I found a solution, but I'm still curious to find out the reason why this isn't working.
Since the original code is thousands of lines I created a simpler example for you to look at.
#include <iostream>
#include <vector>
class Example {
private:
int pValue;
public:
Example(int iValue=0)
{
pValue = iValue;
}
Example(const Example &eSource)
{
pValue = eSource.pValue;
}
Example operator= (const Example &eSource)
{
Example tmp(eSource);
return tmp;
}
int getValue()
{
return pValue;
}
};
int main ()
{
std::vector<Example> myvector;
for (int i=1; i<=8; i++) myvector.push_back(Example(i));
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
myvector.erase (myvector.begin(),myvector.begin()+3);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
return 0;
}
The output is
myvector contains: 1 2 3 4 5
but it should be (an in fact is, if I just use the compiler-generated assignment operator)
myvector contains: 4 5 6 7 8
Your operator= does not do what everyone (including the standard library) thinks it should be doing. It doesn't modify *this at all - it just creates a new copy and returns it.
It's normal to re-use the copy constructor in the copy assignment operator using the copy-and-swap idiom:
Example& operator= (Example eSource)
{
swap(eSource);
return *this;
}
Notice how the operator takes its parameter by value. This means the copy-constructor will be called to construct the parameter, and you can then just swap with that copy, effectively assigning to *this.
Also note that it's expected from operator= to return by reference; when overloading operators, always follow the expected conventions. Even more, the standard actually requires the assignment operator of a CopyAssignable or MoveAssignable type to return a non-const reference (C++11 [moveassignable] and [copyassignable]); so to correctly use the class with the standard library, it has to comply.
Of course, it requires you to implement a swap() function in your class:
void swap(Example &other)
{
using std::swap;
swap(pValue, other.pValue);
}
The function should not raise exceptions (thanks #JamesKanze for mentioning this), no to compromise the exception safety of the operator=.
Also note that you should use the compiler-generated default constructors and assignment operators whenever you can; they can never get out of sync with the class's contents. In your case, there's no reason to provide the custom ones (but I assume the class is a simplified version for posting here).
The assignment operator you found is not correct. All it does is make a copy of eSource, but it's supposed to modify the object on which it is called.
The compiler-generated assignment operator for the class is equivalent to:
Example &operator= (const Example &eSource)
{
pValue = eSource.pValue;
return *this;
}
For this class there's no point implementing operator=, since the compiler-generated version basically cannot be improved on. But if you do implement it, that's the behaviour you want even if you write it differently.
[Alf will say return void, most C++ programmers will say return a reference. Regardless of what you return, the vital behaviour is an assignment to pValue of the value from eSource.pValue. Because that's what the copy assignment operator does: copy from the source to the destination.]
First of all, operator=() should return a reference:
Example& operator=(const Example& eSource)
{
pValue = eSource.pValue;
return *this;
}
Mind that your version returns a copy of tmp so in fact it performs two copies.
Second of all, in your class there's no need to even define custom assignment operator or copy constructor. The ones generated by compiler should be fine.
And third of all, you might be interested in copy-and-swap idiom: What is the copy-and-swap idiom?
Probably the most frequent correct implementation of operator=
will use the copy constructor; you don’t want to write the same
code twice. It will do something like:
Example& Example::operator=( Example const& other )
{
Example tmp( other );
swap( tmp );
return *this;
}
The key here is having a swap member function which swaps the
internal representation, while guaranteeing not to throw.
Just creating a temporary using the copy constructor is not
enough. And a correctly written assignment operator will always
return a reference, and will return *this.

The efficient way to write move copy and move assignment constructors

Are the following assignment and copy move constructors the most efficient?
if anybody have other way please tell me?
I mean what bout std::swap? and calling assignment through copy constructor is safe in the code below?
#include <iostream>
#include <functional>
#include <algorithm>
#include <utility>
using std::cout;
using std::cin;
using std::endl;
using std::bind;
class Widget
{
public:
Widget(int length)
:length_(length),
data_(new int[length])
{
cout<<__FUNCTION__<<"("<<length<<")"<<endl;
}
~Widget()
{
cout<<endl<<__FUNCTION__<<"()"<<endl;
if (data_)
{
cout<<"deleting source"<<endl;
}
else
{
cout<<"deleting Moved object"<<endl;
}
cout<<endl<<endl;
}
Widget(const Widget& other)
:length_(other.length_),
data_(new int[length_])
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
std::copy(other.data_,other.data_ + length_,data_);
}
Widget(Widget&& other)
/*
:length_(other.length_),
data_(new int[length_])*/
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
length_ = 0;
data_ = nullptr;
std::swap(length_,other.length_);
std::swap(data_,other.data_);
}
Widget& operator = (Widget&& other)
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
std::swap(length_,other.length_);
std::swap(data_,other.data_);
return *this;
}
Widget& operator = (const Widget& other)
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
Widget tem(other);
std::swap(length_,tem.length_);
std::swap(data_,tem.data_);
return *this;
}
int length()
{
return length_;
}
private:
int length_;
int* data_;
};
int main()
{
{
Widget w1(1);
Widget w2(std::move(Widget(2)));
w1 = std::move(w2);
}
cout<<"ENTER"<<endl;
cin.get();
return 0;
}
Looks fine from an efficiency POV, but contains an awful lot of duplicated code. I'd
Implement a swap() operator for your class.
Initialize length_ and data_ where they are declared.
Implement operations in terms of other operations whereever possible.
You might want to use std::memcpy instead of std::copy since you're dealing with a raw array anyway. Some compilers will do that for you, but probably not all of them...
Here's a de-duplicated version of your code. Note how there is only one place which needs to know how two instances of Widget are swapped. And only one place which knows how to allocate a Widget of a given size.
Edit: You usually also want to use argument-dependent lookup to locate swap, just in case you ever have non-primitive members.
Edit: Integrated #Philipp's suggestion of making the assignment operator take it's argument by value. That way, it acts as both move assignment and copy assignment operator. In the move case, not that if you pass a temporary, it won't be copied, since the move constructor, not the copy constructor will be used to pass the argument.
Edit: C++11 allows non-cost members to be called on rvalues for compatibility with previous versions of the standard. This allows weird code like Widget(...) = someWidget to compile. Making operator= require an lvalue for this by putting & after the declaration prevents that. Note though that the code is correct even without that restriction, but it nevertheless seems like a good idea, so I added it.
Edit: As Guillaume Papin pointed out, the destructor should use delete[] instead of plain delete. The C++ standard mandates that memory allocated via new [] be deleted via delete [], i.e. it allows new' andnew []` to use different heaps.
class Widget
{
public:
Widget(int length)
:length_(length)
,data_(new int[length])
{}
~Widget()
{
delete[] data_;
}
Widget(const Widget& other)
:Widget(other.length_)
{
std::copy(other.data_, other.data_ + length_, data_);
}
Widget(Widget&& other)
{
swap(*this, other);
}
Widget& operator= (Widget other) &
{
swap(*this, other);
return *this;
}
int length() const
{
return length_;
}
private:
friend void swap(Widget& a, Widget& b);
int length_ = 0;
int* data_ = nullptr;
};
void swap(Widget& a, Widget& b) {
using std::swap;
swap(a.length_, b.length_);
swap(a.data_, b.data_);
}
The answer is in response to #Abdulrhman's complaint in the comments above that things fail for some (obscure) sequences of assignments. Put into a seperate answer because it's more readable that way.
The complaint was that
Widget w(2);
w = Widget(1) = std::move(w);
crashes. Here's the output I get from
Widget w(2);
w.data()[0] = 0xDEAD; w.data()[1] = 0xBEEF;
w = Widget(1) = std::move(w);
std::cerr << std::hex << w.data()[0] << w.data()[1] << std::endl;
with some code added to Widget to log constructor, destructor and assignment operator calls. Interleaves are comments about where those calls come from
w is constructed
0x7fff619c36c0: [constructor] allocated 2#0x1043dff80
temporary Widget(1) is constructed
0x7fff619c37c0: [constructor] allocated 1#0x1043e0180
first (right) assignment operator argument is constructed. w is empty afterwards!
0x7fff619c3800: [default constructor] empty
0x7fff619c3800: [move constructor] stealing 2#0x1043dff80 from 0x7fff619c36c0, replacing with 0#0x0
first assignment operator does it's job, i.e. moves from by-value argument.
0x7fff619c37c0: [assignment] stealing 2#0x1043dff80 from 0x7fff619c3800, replacing with 1#0x1043e0180
second (left) assignment operator arguments is constructed
0x7fff619c3780: [constructor] allocated 2#0x1043e0280
0x7fff619c3780: [copy constructor] copying 2#0x1043dff80 from 0x7fff619c37c0
second assignment operator does it's job, i.e. moves from by-value argument
0x7fff619c36c0: [assignment] stealing 2#0x1043e0280 from 0x7fff619c3780, replacing with 0#0x0
second assingment operator's by-value argument is destructed
0x7fff619c3780: [destructor] deleting 0#0x0
first assignment operator's by-value argument is destructed
0x7fff619c3800: [destructor] deleting 1#0x1043e0180
temporary created as Widget(1) is destructed.
0x7fff619c37c0: [destructor] deleting 2#0x1043dff80
data contains in "w" after assignments.
deadbeef
finally, "w" is destructed.
0x7fff619c36c0: [destructor] deleting 2#0x1043e0280
I can see no problem there, and compiling this with clang and -faddress-sanitizer, -fcatch-undefined-behaviour doesn't complain either.
Note, though, that the second assigment (the left = operator) copies instead of moving. This is because the first (right) assignment operator returns an lvalue-reference.
You don't need so many swaps and assignments in your move constructor. This:
Widget(Widget&& other) :
length( other.length_ ), data( other.data_ )
{
other.length_ = 0;
other.data_ = nullptr;
}
does the minimum work for the move constructor: 4 assignments in total. Your version had 8, counting the ones in the calls to swap().
Your move assignment is OK, but you might want to consider just writing one operator=() to cover both cases:
Widget &operator=( Widget other ) {
delete data_;
data_ = other.data_;
other.data_ = nullptr;
length_ = other.length_;
other.length_ = 0;
return *this;
}
This is slightly less efficient than your version, in that it can move twice.

Why there is a copy before assign?

I am doing the following test:
#include <iostream>
#include <vector>
using namespace std;
class A
{
private:
int i;
public:
A():i(1){cout<<"A constr"<<endl;}
A(const A & a):i(a.i){cout<<"A copy"<<endl;}
virtual ~A(){cout<<"destruct A"<<endl;}
void operator=(const A a){cout<<"A assign"<<endl;}
};
int main()
{
A o1;
A o2;
o2=o1;
}
And the output is:
A constr
A constr
A copy
A assign
destruct A
destruct A
destruct A
It seems that "o2=o1" did a copy first followed by an assignment, and I wonder what's the story behind it. Thanks!
Because you pass by value into your assignment operator:
void operator=(const A a)
You probably meant to pass by reference and you should also return a reference to the assigned-to object:
A& operator=(const A& a) { std::cout << "A assign" << std::endl; return *this; }
You seem to set up you assignment operator to be implemented properly:
T& T::operator= (T value) {
value. swap(*this);
return *this;
}
The argument is passed by copy to the assigment operator and the compiler actually needed to do this copy in your set up. If you had passed a temporary the copy could have been avoided:
o2 = A();
Thus, the implementation above actually has a few interesting properties:
it leverages already written functions: the copy constructor is either generated or written but does the Right Thing and if you want to have an assignment you probably want to have swap() member as well
the assignment is strong exception safe if the swap() operation is non-throwing as it should be. When allocators enter the picture things need to be done slightly different, though
the assignment tries to avoid actual copy operations as the copy during argument passing can be elided in some cases, i.e. the content is just swap()ed into place

Class Assignment Operators

I made the following operator overloading test:
#include <iostream>
#include <string>
using namespace std;
class TestClass
{
string ClassName;
public:
TestClass(string Name)
{
ClassName = Name;
cout << ClassName << " constructed." << endl;
}
~TestClass()
{
cout << ClassName << " destructed." << endl;
}
void operator=(TestClass Other)
{
cout << ClassName << " in operator=" << endl;
cout << "The address of the other class is " << &Other << "." << endl;
}
};
int main()
{
TestClass FirstInstance("FirstInstance");
TestClass SecondInstance("SecondInstance");
FirstInstance = SecondInstance;
SecondInstance = FirstInstance;
return 0;
}
The assignment operator behaves as-expected, outputting the address of the other instance.
Now, how would I actually assign something from the other instance? For example, something like this:
void operator=(TestClass Other)
{
ClassName = Other.ClassName;
}
The code you've shown would do it. No one would consider it to be a particularly good implementation, though.
This conforms to what is expected of an assignment operator:
TestClass& operator=(TestClass other)
{
using std::swap;
swap(ClassName, other.ClassName);
// repeat for other member variables;
return *this;
}
BTW, you talk about "other class", but you have only one class, and multiple instances of that class.
The traditional canonical form of the assignment operator looks like this:
TestClass& operator=(const TestClass& Other);
(you don't want to invoke the copy constructor for assignment, too) and it returns a reference to *this.
A naive implementation would assign each data member individually:
TestClass& operator=(const TestClass& Other)
{
ClassName = Other.ClassName;
return *this;
}
(Note that this is exactly what the compiler-generated assignment operator would do, so it's pretty useless to overload it. I take it that this is for exercising, though.)
A better approach would be to employ the Copy-And-Swap idiom. (If you find GMan's answer too overwhelming, try mine, which is less exhaustive. :)) Note that C&S employs the copy constructor and destructor to do assignment and therefore requires the object to be passed per copy, as you had in your question:
TestClass& operator=(TestClass Other)
almost all said, a few notes:
check for self-assignment, i.e. if (&other != this) // assign
look here for an excellent guide on operator overloading
Traditionnaly the assignment operator and the copy constructor are defined passing a const reference, and not with a copy by value mechanism.
class TestClass
{
public:
//...
TestClass& operator=(const TestClass& Other)
{
m_ClassName= Other.m_ClassName;
return *this;
}
private:
std::string m_ClassName;
}
EDIT: I corrected because I had put code that didnt return the TestClass& (c.f. #sbi 's answer)
You are correct about how to copy the contents from the other class. Simple objects can just be assigned using operator=.
However, be wary of cases where TestClass contains pointer members -- if you just assign the pointer using operator=, then both objects will have pointers pointing to the same memory, which may not be what you want. You may instead need to make sure you allocate some new memory and copy the pointed-to data into it so both objects have their own copy of the data. Remember you also need to properly deallocate the memory already pointed to by the assigned-to object before allocating a new block for the copied data.
By the way, you should probably declare your operator= like this:
TestClass & operator=(const TestClass & Other)
{
ClassName = Other.ClassName;
return *this;
}
This is the general convention used when overloading operator=. The return statement allows chaining of assignments (like a = b = c) and passing the parameter by const reference avoids copying Other on its way into the function call.