This question already has answers here:
Why and when delete copy constructor and operator=
(2 answers)
Closed 3 years ago.
I am often seeing such (simplified) code:
class A {
public:
A(int a) :a{a} {}
A(const A&) = delete;
A& operator=(const A&) = delete;
private:
int a;
}
Then, throughout the program, the class A is instantiated only once.
What are the practical reaons to delete a copy constructor and operator= and at the same time not make the class Singleton?
If you have a class that have vars allocating dynamic memory and you don't want to make a suitable copy ctor and cpy assignment operator to allocate a new memory to avoide having two pointers pointing to the same thing, you can delete the whole cpy ctor and cpy assignment operator.
If you want to disallow passing the object by value, you may delete them too.
When to delete copy constructor and assignment operator?
Copy constructor (and assignment) should be defined when ever the implicitly generated one violates any class invariant.
It should be defined as deleted when it cannot be written in a way that wouldn't have undesirable or surprising behaviour.
Probably the simplest example is the class std::unique_ptr. As the name implies, it has unique ownership of a pointer value. Copying the internal pointer would violate the invariant of unique ownership. That's what the implicit copy constructor (and assignment) would do. But there is no reasonable alternative either. Maybe you could implement a copy constructor that dynamically allocates a new object, and copy-initialises it from the originally pointed object. But then this pointer would have different behaviour from normal pointers whose copy will not cause allocation or creation of new pointed objects, which may be surprising and undesirable. Furthermore, std::unique_ptr needs to also be usable with pointed types that themselves might not be copyable.
Related
I'm trying to initialize one object into other object using copy constructor. I'm puzzled that if I comment out copy constructor it initializes fine but with following code it does not.
class TDateTime : public TData {
public:
TDateTime() : TData(EDataStateInvalid) {}
TDateTime(const tm& aTm){};
TDateTime(int aTm_sec, int aTm_min, int aTm_hour,
int aTm_mday, int aTm_mon, int aTm_year, int aTm_wday,int aTm_isdst){
value.tm_sec=aTm_sec;
value.tm_min=aTm_min;
value.tm_hour=aTm_hour;
value.tm_mday=aTm_mday;
value.tm_mon=aTm_mon;
value.tm_year=aTm_year;
value.tm_wday=aTm_wday;
value.tm_isdst=aTm_isdst;
};
virtual ~TDateTime() {cout<<"Destroying TDateTime ";};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
private:
tm value;
};
main.cpp
tm=createDateTime(x);
TDateTime aDateTimeFrom(tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm. tm_wday,0);
TDateTime aDateTimeTo(aDateTimeFrom);
if I comment out the copy constructor it copies fine. If I remove {} then compiler complains about undefined symbol.
Can you suggest what is wrong here?
Based on answer about empty copy constructor does nothing, I comment it out and copy is perfect but I have another problem. If I do
TDateTime aDateTime;
aDateTime=aDateTimeFrom;
aDateTime has all junk values. Any pointers on this?
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
Your copy constructor does nothing. There is no magic involved with user-written copy constructors; if you don't make them do anything, then they will not do anything.
More precisely, a new instance is created, but its members are left uninitialised or are default-initialised.
While we're at it...
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
Same problem here. Your copy-assignment operator does not do anything.
By convention, it should also not return a const reference but a non-const one.
It may be worth the mention that your intution seems to be correct, as your goal should indeed be to create classes which don't require any self-written copy constructors or copy-assignment operators because all members know how to correctly copy or copy-assign themselves (like std::string or std::vector or std::shared_ptr). But in that case, rather than defining the member functions with empty implementations, you just don't declare them at all in your code, such that the compiler can handle everything automatically.
And finally, one other thing: A good rule of thumb for C++ classes is that they should either have virtual functions and disable copying (sometimes called "identity classes") or have no virtual functions and allow copying (sometimes called "value classes"). Something like a virtual assignment operator often indicates an overly complicated, hard-to-use and error-prone class design.
A compiler generates a copy constructor which performs member-wise copy if the user hasn't declared a copy constructor. If the user does declare a copy-constructor, then the copy constructor does what the user has told it to, in your case - exactly nothing.
TDateTime(const TDateTime& aInstance){ /* empty body*/};
Your define a copy constructor which does not do anything.
In your case you don't really need a copy constructor and/or copy assignment operator, the compiler generated versions would be enough (it would be wise to make sure/recheck that tm class can handle the copying).
There is a rule of three, which states that one needs copy constructor and copy assignment operator if one defines a destructor. But it is only a rule of thumb and not an actual necessity. In your case there is no memory management involved and you use the destructor only for logging.
So do not declare a copy constructor at all (your assign operator has the same flaw by the way - it does not copy anything) and let the compiler do the work.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I have a "twisted" question...
Suppose to have a class like
class MyClass {
public:
MyClass();
~MyClass();
MyClass& operator=(const MyClass& obj);
private:
int* mem;
};
where basically MyClass inits somehow mem (with a new call), the ~MyClass() deallocates mem with the delete operator.
Suppose moreover the operator = is overloaded with the code
MyClass& operator=(const MyClass& obj) {
if(this != &obj) {
//allocate memory of "this" with the "new" operator and copy "obj" data;
}
return *this;
}
my question is basically the following... With the following sequence of statements
//statement 1 for short
MyClass my_obj = some_obj_of_MyClass;
i guess everything is fine since the operator = allocates memory and copies the data, but with the following
//statement 2 for short
MyClass obj; //allocate memory for "mem"
obj = some_obj_of_MyClass;
if think it is not correct the implementation i proposed since i don't delete memory allocated early. I could call the destructor inside the assignment operator block, but in that case probably the statement 1 wouldn't be safe.
So what it is a safe way to implement everything?
I guess the problem here can be to understand when the destructor is called or how to implement it properly.
Your code violates the rule of three: Whenever a class provides a custom
copy constructor
copy assignment operator
destructor
it should likely provide all three. Because, if any of these is omitted, it is possible to construct use cases where bad things happen. For example, contrary to intuition, the statement
MyClass my_obj = some_obj_of_MyClass;
does not call the assignment operator. It calls the copy constructor, which you have not provided. As such, the default copy constructor is used which simply copies the pointer. Once either my_obj or some_obj_of_MyClass is destructed, the other will have a pointer to the deleted memory region.
On the other hand, the statements
MyClass obj;
obj = some_obj_of_MyClass;
will first default construct obj, and then call the assignment operator on it. The assignment operator must be written in a way that it works correctly in every possible state of obj (i. e. it must not leak memory or double delete memory). That is, if obj.mem is allocated, the assignment operator must either reuse that memory or deallocate it (possibly replacing it with a new allocation). If obj.mem can be a null pointer, then the assignment operator must include special handling of this special case.
So, your choice is basically, whether you want to allow the mem pointer to become a null pointer, If you don't allow this, your default constructor must allocate a dummy memory region that can be deallocated by the assignment operator.
You can also work around the rule of three by deleting the unimplemented functions. Your class could be declared like this:
class MyClass {
public:
MyClass();
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass& obj);
~MyClass();
private:
int* mem;
};
This would disallow the statement
MyClass my_obj = some_obj_of_MyClass;
forcing user code to use the more verbose
MyClass obj;
obj = some_obj_of_MyClass;
but which makes the implementation of MyClass a bit simpler.
Suppose I have a class:
class State {
std::shared_ptr<Graph> _graph;
public:
State():_graph(new Graph){}
};
With regards to rule of three, apparently no need to free _graph in destructor as it is a smart pointer. The question is, do I need to write copy constructor and assignment operator for it?
Considering following:
State s1;
State s2 = s1;
What will happen with the second line?
Looks like it will be s2._graph = s1._graph;, pointer shared, so we are safe?
Default generated copy ctors and assignment operators use the ones provided in the class members.
The shared_ptr copy constructor "shares ownership of the object".
The shared_ptr assignment operator replaces and shares.
If this is the behavior you want, their is no need to explicitly declare the copy ctor and the assignment operator.
I recently revisited the copy constructor, assignment operator, copy swap idom seen here:
What is the copy-and-swap idiom?
and many other places -
The Above link is an excellent post - but I still had a few more questions -
These questions are answered in a bunch of places, on stackoverflow and many other sites, but I have not seen a lot of consistency -
1 - Should you have try-catch around the areas where we allocate the new memory for a deep copy in the copy constructor ? (Ive seen it both ways)
2 - With regards to inheritance for both the copy constructor and assignment operator, when should the base class functions be called, and when should these functions be virtual?
3 - Is std::copy the best way for duplicating memory in the copy constructor? I have seen it with memcpy, and seen others say memcpy the worst thing on earth.
Consider the example Below (Thanks for all the feedback), it prompted some additional questions:
4 - Should we be checking for self assignment? If so where
5 - Off topic question, but I have seen swapped used as :
std::copy(Other.Data,Other.Data + size,Data);
should it be:
std::copy(Other.Data,Other.Data + (size-1),Data);
if swap goes from 'First to Last' and the 0th element is Other.Data?
6 - Why doesn't the commented out constructor work (I had to change size to mysize) - is assume this means regardless of the order I write them, the constructor will always call the allocation element first?
7 - Any other comments on my implementation? I know the code is useless but i'm just trying to illustrate a point.
class TBar
{
public:
//Swap Function
void swap(TBar &One, TBar &Two)
{
std::swap(One.b,Two.b);
std::swap(One.a,Two.a);
}
int a;
int *b;
TBar& operator=(TBar Other)
{
swap(Other,*this);
return (*this);
}
TBar() : a(0), b(new int) {} //We Always Allocate the int
TBar(TBar const &Other) : a(Other.a), b(new int)
{
std::copy(Other.b,Other.b,b);
*b = 22; //Just to have something
}
virtual ~TBar() { delete b;}
};
class TSuperFoo : public TBar
{
public:
int* Data;
int size;
//Swap Function for copy swap
void swap (TSuperFoo &One, TSuperFoo &Two)
{
std::swap(static_cast<TBar&>(One),static_cast<TBar&>(Two));
std::swap(One.Data,Two.Data);
std::swap(One.size,Two.size);
}
//Default Constructor
TSuperFoo(int mysize = 5) : TBar(), size(mysize), Data(new int[mysize]) {}
//TSuperFoo(int mysize = 5) : TBar(), size(mysize), Data(new int[size]) {} *1
//Copy Constructor
TSuperFoo(TSuperFoo const &Other) : TBar(Other), size(Other.size), Data(new int[Other.size]) // I need [Other.size]! not sizw
{
std::copy(Other.Data,Other.Data + size,Data); // Should this be (size-1) if std::copy is First -> Last? *2
}
//Assignment Operator
TSuperFoo& operator=(TSuperFoo Other)
{
swap(Other,(*this));
return (*this);
}
~TSuperFoo() { delete[] Data;}
};
If you allocate memory then you need to ensure that it is freed in the case of an exception being thrown. You can do this with an explicit try/catch, or you can use a smart pointer such as std::unique_ptr to hold the memory, which will then be automatically deleted when the smart pointer is destroyed by stack unwinding.
You very rarely need a virtual assignment operator. Call the base class copy constructor in the member initialization list, and base-class assignment operator first in the derived assignment operator if you are doing a memberwise assignment --- if you are doing copy/swap then you don't need to call the base class assignment in your derived assignment operator, provided that copy and swap are implemented correctly.
std::copy works with objects, and will correctly call copy constructors. If you have plain POD objects then memcpy will work just as well. I'd go for std::copy in most cases though --- it should be optimized to memcpy under the hood anyway for PODs, and it avoids the potential for errors should you add a copy constructor later.
[Updates for updated question]
With copy/swap as written there is no need to check for self-assignment, and indeed no way of doing so --- by the time you enter the assignment operator other is a copy, and you have no way of knowing what the source object was. This just means that self-assignment will still do a copy/swap.
std::copy takes a pair of iterators (first, first+size) as input. This allows for empty ranges, and is the same as every range-based algorithm in the standard library.
The commented out constructor doesn't work because the members are initialized in the order they are declared, regardless of the order in the member initializer list. Consequently, Data is always initialized first. If the initialization depends on size then it will get a duff value since size hasn't been initialized yet. If you swap the declarations of size and data then this constructor will work fine. Good compilers will warn about the order of member initialization not matching the order of declarations.
1 - Should you have try-catch around the areas where we allocate the new memory for a deep copy in the copy constructor ?
In general, you should only catch an exception if you can handle it. If you have a way of dealing with an out-of-memory condition locally, then catch it; otherwise, let it go.
You should certainly not return normally from a constructor if construction has failed - that would leave the caller with an invalid object, and no way to know that it's invalid.
2 - With regards to inheritance for both the copy constructor and assignment operator, when should the base class functions be called, and when should these functions be virtual?
A constructor can't be virtual, since virtual functions can only be dispatched by an object, and there is no object before you create it. Usually, you wouldn't make assignment operators virtual either; copyable and assignable classes are usually treated as non-polymorphic "value" types.
Usually, you'd call the base class copy constructor from the initialiser list:
Derived(Derived const & other) : Base(other), <derived members> {}
and if you're using the copy-and-swap idiom, then your assignment operator wouldn't need to worry about the base class; that would be handled by the swap:
void swap(Derived & a, Derived & b) {
using namespace std;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
// and swap the derived class members too
}
Derived & Derived::operator=(Derived other) {
swap(*this, other);
return *this;
}
3 - Is std::copy the best way for duplicating memory in the copy constructor? I have seen it with memcopy, and seen others say memcopy the worst thing on earth.
It's rather unusual to be dealing with raw memory; usually your class contains objects, and often objects can't be correctly copied by simply copying their memory. You copy objects using their copy constructors or assignment operators, and std::copy will use the assignment operator to copy an array of objects (or, more generally, a sequence of objects).
If you really want, you could use memcpy to copy POD (plain old data) objects and arrays; but std::copy is less error-prone (since you don't need to provide the object size), less fragile (since it won't break if you change the objects to be non-POD) and potentially faster (since the object size and alignment are known at compile time).
If the constructor for what you're deep copying may throw something
you can handle, go ahead and catch it. I'd just let memory
allocation exceptions propagate, though.
Copy constructors (or any constructors) can't be virtual. Include a
base class initializer for these. Copy assignment operators should
delegate to the base class even if they're virtual.
memcpy() is too low-level for copying class types in C++ and can lead to undefined behavior. I think std::copy is usually a better choice.
try-catch can be used when you have to undo something. Otherwise, just let the bad_alloc propagate to the caller.
Calling the base class' copy constructor or assignment operator is the standard way of letting is handle its copying. I have never seen a use case for a virtual assignment operator, so I guess they are rare.
std::copy has the advantage that it copies class objects correctly. memcpy is rather limited on what types it can handle.
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