As i know, when we assign one object is another default copy constructor will be called.
class class1 obj1;
class class2 obj2;
obj1(obj2); //default copy constructor will be called by compiler
So, when should I write explicitly the copy constructor?
In your case the copy-assignment operator will be called, not the copy-constructor. To call the copy-constructor you would have do to e.g.
class1 obj1;
class1 obj2 = obj1; // Invokes the copy-constructor in obj2
A good idea when to write a copy-constructor (or a copy-assignment operator, or a destructor) you can see by reading about the rule of three. In short, if you have any of a destructor, copy-constructor or copy-assignment operator, then you should probably have all of them.
Also, while the compiler will auto-generate copy-constructor and copy-assignment operator for you if you do not provide your own, you have to remember that those auto-generated function will only do a shallow copy. If you have e.g. pointers to memory you allocate in the object, the auto-generated functions will only copy the actual pointer, and not what it points to. This means that after a copy you have two objects both pointing to the same memory. If you delete the pointer in the destructor, and one of the objects are destructed, the other object will still have its pointer, but it will now point to deleted memory.
You will get a default copy constructor when you don't write one, provided you don't add any of the three or five to your class : destructor, copy or move assignment or constructor.
Sometimes this does the right thing. For example, if you just need a shallow copy, or if the member's corresponding functions fo the right thing, for example smart pointers.
If an object exist prior to the assign, then it does not involve a construction but the assignment operator, signatures are:
T& operator=( T const & ); // from l-value ref
T& operator=( T && ); // from r-value ref, since c++11
A frequent strategy is to write the assignment operator as the idiom "copy and swap" :
T& operator=( T const & o ) {
T val( o ); // you need to write the copy ctor
swap(*this,o); // you need to write the swap
return *this;
}
T& operator=( T && o ) {
T val( std::move(o) ); // you need to write the move ctor
swap(*this,o); // you need to write the swap
return *this;
}
The c++11 version of that strategy
T& operator=( T o ) noexcept { // copy done before the operator that can be noexcept ( swap have to too)
swap(*this,o); // you need to write the swap
return *this;
}
In some cases you will find that the way your objects should be copied is not trivial.
If you consider the class :
class Car {
string BrandName;
int NumberOfPassenger;
}
Then it is clear that when you'll be copying two objects, you'll simply want to copy them member by member. There's nothing special to do here so the defaut copy constructor will work just fine.
But imagine that the class is instead :
class Car {
string BrandName;
int NumberOfPassenger;
Mechanics EngineeringStuff;
}
Here Mechanics is a reference type. What the copy constructor will do is simply copying the reference to the new object, so both cars - car1 and car2 - will share the same EngineeringStuff. But a more natural behaviour would be to allocate manually a new Mechanics object when performing the copy, so the cars don't share the same wheels, motors etc...
More generally, it's usually when you have to deal with reference types or certain kind of business logic that you will need to explicitly write your copy constructor.
Related
The return type will be different of course, but the concept is the same: copying the data from one object to another, right?
The concepts are fundamentally different; the copy constructor creates a new object where one doesn’t exist (and does not return anything – not even void), and the assignment operator updates an object that already exists.
No. While the copy assignment operator does copy data to another object, the copy constructor initializes a new object with the copied data. As such, it will use its member initializer list to invoke its member's copy constructors recursively, while the copy-assignment operator will invoke other copy-assignment operators.
struct Foo {
Foo(Foo const &orig)
: data{oring.data} { }
Foo &operator = (Foo const &orig) {
data = orig.data;
return *this;
}
private:
std::string data;
};
The copy constructor initializes the new object with an already existing object.
The copy assignment assigns the value of one object to another object both of which are already in existence.
I am writing a c++11+ standards compliant class, and it is time for me to implement the rule of 5.
Destructor
Copy Constructor
Move Constructor
Copy Assignment Operator
Move Assignment Operator
I had a question about copy/move constructors/assignment. It is my understanding that a copy constructor/assignment should make a copy (shallow, deep?) of your class. In the case that your class has unique members, such as a unique_ptr, there are two scenarios I foresee.
Make a deep copy of the object
I am not sure, in my case, how I would make a deep copy (see code below).
Move the object to the other class
In my opinion, moving the pointer in a copy constructor has unintended side effects for a user, as they are expecting a copy, and not a move, and the original object being copied would no longer function.
Making a copy could also be problematic, however, in my case, the curl object could contain sensitive information such as cookies or a password?
What is the defacto way to create copy and move constructors/assignment for classes with these constraints? To deep copy, to move, or not explicitly and implicitly define a copy constructor (does the delete keyword do this)?
// client.h
#pragma once
#include <Poco/URI.h>
#include <curl/curl.h>
class client
{
public:
typedef Poco::URI uri_type;
// Constructor
client(const uri_type & auth);
// Destructor
virtual ~client();
// Copy constructor
client(const client & other);
// Move constructor
client(client && other);
// Copy assignment
client & operator=(const client & other);
// Move assignment operator
client & operator=(client && other);
private:
uri_type auth_;
// ... other variables (both unique and copyable) ommitted for simplicity.
std::unique_ptr<CURL, void(*)(CURL*)> ptr_curl_;
};
// client.cpp
#include <memory>
#include <Poco/URI.h>
#include <curl/curl.h>
#include "client.h"
// Constructor
client::client(const uri_type & auth)
: auth_(auth)
, ptr_curl_(curl_easy_init(), curl_easy_cleanup)
{
curl_global_init(CURL_GLOBAL_DEFAULT);
}
// Destructor
client::~client()
{
curl_global_cleanup();
}
// Copy constructor
client::client(const client & other)
{
// ... deep copy? move?
// how would you deep copy a unique_ptr<CURL>?
}
// Move constructor
client::client(client && other)
{
std::swap(*this, other);
}
// Copy assignment
client & client::operator=(const client & other)
{
// Cant get this to work by making the copy happen in the parameter.
client temp(other);
std::swap(*this, temp);
return *this;
}
// Move assignment operator
client & client::operator=(client && other)
{
return *this;
}
As the name indicates, a copy constructor/assignment operator should always COPY and not move its members, where copy usually means deep copy.
Remember: By default, all objects in c++ should have value semantics, i.e. they should behave like an int.
Furthermore, the terminology in your post indicates that you are confusing unique objects (singletons) with objects pointed to by unique_ptr. Most non-copyable objects are handlers (like unique_ptr handles objects on the heap) in which case you'd copy whatever they handle. If that is not possible, then most likely, it doesn't make sense to implement a copy constructor of your object at all.
If your object holds an owning reference to a unique resource (from which there can be only one instance in your project),then the first question would be: can it be shared? -> use shared_ptr. If not -> don't copy.
If your object holds a non-owning reference to a unique ressource (raw pointer or reference) copy the reference. In both cases, be aware that you now have two objects, that share part of their state, which might be dangerous even in non-multithreaded applications.
For some types, having a copy constructor is inappropriate. That includes most types that semantically contain non-copyable types. (Don't count the unique_ptr, do count the CURL instance)
If libcurl has a "duplicate_handle" sort of function, then your copy constructor should use it to initialize the unique_ptr in the copy. Otherwise, you should delete your copy constructor and only implement move.
I need to write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied. The situation is as follows:
class C{
// C class stuff
};
class A{
public:
public A();
public A(const A& a);
private:
std::unique_ptr<C> c_;
}
class B{
public:
B(const A& b) : a_(a){}
private:
A a_;
};
How should I implement the copy constructor for A?
Your intent or approach is wrong, I guess.
The copy-constructor is meant to create a copy of the argument, but since unique_ptr maintains sole ownership one cannot make a copy of it. You could in fact make the unique_ptr member mutable and then move the resource it points to in the copy-constructor but that would be absolutely insane (this is what std::auto_ptr does and this is why it's deprecated).
Therefore either you need to:
add a move-constructor to A and B (+ make copy-constructor deleted)
switch from unique_ptr to shared_ptr, but only if C is actually meant to be shared
There's also a third option, which is to make a copy of the object pointed to by the unique_ptr in A's copy-constructor, i.e.:
A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}
Obviously you cannot just do an assignment of std::unique_ptrs as their assignment operator is deleted. This is intentional to force the programmer to define the behavior he wants.
The new item takes ownership of c_, invalidating the original item.
The new item makes a copy of c_, retaining the original items validity.
The new item shares ownership of c_ so that both the new and original items reference the same object.
In case 1 what you're looking for is a move constructor, and the default move constructor will work fine. So you don't need to write any code, you can just do:
A temp;
A foo(std::move(temp));
Note that temp is invalid after it is moved.
In case 2 you'll need to add a custom copy constructor to A to create a copy of the original's c_:
A(const A& a):c_(new C(*(a.c_))){}
After defining this in A you can do:
A foo(A());
Note that this depends upon C's copy constructor being functional.
In case 3 you'll need to fundamentally change A from using a std::unique_ptr to using a std::shared_ptr, so the definition of c_ would become:
std::shared_ptr<C> c_;
Your construction of c_ would be identical to what you're already using for the std::unique_ptr version of c_. So just using the default implementations you could do:
A foo;
A bar(foo);
And now foo and bar point to the same C object, and share ownership of it. This shared object will not be deleted until all shared_ptrs referencing it have been deleted.
Technically, to
” write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied
you can just do this:
class Bad
{
private:
unique_ptr<int> p_;
public:
Bad(): p_( new int(666) ) {}
Bad( Bad& other )
: p_( move( other.p_ ) )
{}
};
Because a copy constructor can have also this signature, plus two more, in addition to the more conventional Bad( const Bad& ).
I named that class Bad because it's really bad, it just does not make sense to do this thing except as sabotage of someone else's code.
Instead of a copy constructor that doesn't copy,
implement a move constructor that moves, or
implement an ordinary copy constructor that copies, or
change the class design to e.g. shared ownership.
I understand the need for deep copies, and to ensure my code behaves as desired, I am writing a copy ctor, assignment operator, and dtor for my class.
However, it seems to me that in every case, an assignment operator has to do first what the destructor does (deallocate any dynamically allocated memory, to prevent memory leaks), and then what the copy constructor does (make deep copies of all dynamically allocated data and copy those into the instance being constructed).
Is there a case where an assignment operator should conceptually do something other than the following?
class SomeClass{
//member data, copy ctor, dtor
SomeClass& operator=(SomeClass const& rhs){
//what the destructor does
//what the copy constructor does
}
};
The code is practically identical, and seems like a waste of time to rewrite. Other than invoking the destructor directly at the beginning of the assignment operator, I can't think of a way to reuse the copy constructor code I've already written, since I believe doing something like
*this=rhs
would only recursively invoke the assignment operator, since techinically, "this" has already been constructed.
As mentioned in the comments, your concerns about code duplication is addressed by applying the copy-and-swap idiom:
class SomeClass{
//member data, copy ctor, dtor
SomeClass& operator=(SomeClass rhs){
swap(*this, rhs);
return *this;
}
friend void swap(SomeClass& first, SomeClass& second) {
using std::swap;
swap(first.data, second.data);
//... etc. for other data members
}
};
You have to implement the additional swap function, but your copy constructor and destructor code is reused in a natural way. The copy constructor is used when the source of the assignment is passed to the assignment operator, and the destructor is reused when the argument is destructed when the assignment operator returns.
If the operator= is properly defined, is it OK to use the following as copy constructor?
MyClass::MyClass(MyClass const &_copy)
{
*this = _copy;
}
If all members of MyClass have a default constructor, yes.
Note that usually it is the other way around:
class MyClass
{
public:
MyClass(MyClass const&); // Implemented
void swap(MyClass&) throw(); // Implemented
MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
};
We pass by value in operator= so that the copy constructor gets called. Note that everything is exception safe, since swap is guaranteed not to throw (you have to ensure this in your implementation).
EDIT, as requested, about the call-by-value stuff: The operator= could be written as
MyClass& MyClass::operator=(MyClass const& rhs)
{
MyClass tmp(rhs);
tmp.swap(*this);
return *this;
}
C++ students are usually told to pass class instances by reference because the copy constructor gets called if they are passed by value. In our case, we have to copy rhs anyway, so passing by value is fine.
Thus, the operator= (first version, call by value) reads:
Make a copy of rhs (via the copy constructor, automatically called)
Swap its contents with *this
Return *this and let rhs (which contains the old value) be destroyed at method exit.
Now, we have an extra bonus with this call-by-value. If the object being passed to operator= (or any function which gets its arguments by value) is a temporary object, the compiler can (and usually does) make no copy at all. This is called copy elision.
Therefore, if rhs is temporary, no copy is made. We are left with:
Swap this and rhs contents
Destroy rhs
So passing by value is in this case more efficient than passing by reference.
It is more advisable to implement operator= in terms of an exception safe copy constructor. See Example 4. in this from Herb Sutter for an explanation of the technique and why it's a good idea.
http://www.gotw.ca/gotw/059.htm
This implementation implies that the default constructors for all the data members (and base classes) are available and accessible from MyClass, because they will be called first, before making the assignment. Even in this case, having this extra call for the constructors might be expensive (depending on the content of the class).
I would still stick to separate implementation of the copy constructor through initialization list, even if it means writing more code.
Another thing: This implementation might have side effects (e.g. if you have dynamically allocated members).
While the end result is the same, the members are first default initialized, only copied after that.
With 'expensive' members, you better copy-construct with an initializer list.
struct C {
ExpensiveType member;
C( const C& other ): member(other.member) {}
};
};
I would say this is not okay if MyClass allocates memory or is mutable.
yes.
personally, if your class doesn't have pointers though I'd not overload the equal operator or write the copy constructor and let the compiler do it for you; it will implement a shallow copy and you'll know for sure that all member data is copied, whereas if you overload the = op; and then add a data member and then forget to update the overload you'll have a problem.
#Alexandre - I am not sure about passing by value in assignment operator. What is the advantage you will get by calling copy constructor there? Is this going to fasten the assignment operator?
P.S. I don't know how to write comments. Or may be I am not allowed to write comments.
It is technically OK, if you have a working assignment operator (copy operator).
However, you should prefer copy-and-swap because:
Exception safety is easier with copy-swap
Most logical separation of concerns:
The copy-ctor is about allocating the resources it needs (to copy the other stuff).
The swap function is (mostly) only about exchanging internal "handles" and doesn't need to do resource (de)allocation
The destructor is about resource deallocation
Copy-and-swap naturally combines these three function in the assignment/copy operator