If I declare a class like, (no dynamic memory allocation, no pointer):
class A{
int a,b;
public:
A();
A(int,int);
A& operator=(const A);
};
Is it safe not to declare a copy constructor? How does the default copy constructor looks like?
A& A::operator=(const A other)
{
a=other.a;
b=other.b;
return *this;
}
Even If I do not declare a copy constructor, the default one will be called when I call operator=()
EDIT:
the default destructor is:
A::~A(){}
so it's not needed here
The rule is that if you need to provide either:
copy constructor or
destructor or
copy assignment operator
then you probably need to provide all three of them. This rule is known as Rule of Three.
Is it safe not to declare a copy constructor?
It is safe.
Do you have to for your example case?
Not really. To be specific the rule of three governs that. Check the linked question for more details on that.
How does the default copy constructor looks like?
I gather this is asking, What does the default copy constructor do.
This is answered in:
C++03 Standard 12.8 Copying class objects:
Para 8:
The implicitly-defined copy constructor for class X performs a memberwise copy of its subobjects. The order of copying is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Each subobject is copied in the manner appropriate to its type:
— if the subobject is of class type, the copy constructor for the class is used;
— if the subobject is an array, each element is copied, in the manner appropriate to the element type;
— if the subobject is of scalar type, the built-in assignment operator is used.
Virtual base class subobjects shall be copied only once by the implicitly-defined copy constructor (see 12.6.2).
Even If I not declare a copy constructor, the default one will be called when I call operator=()
A copy constructor is invoked only when a copy of the class object needs to be created. This involves copies of objects created while passing to or returning from functions.
Your copy assignment operator passes the object A by value, this pass by value is achieved by passing a copy of the object through copy constructor and hence the call to copy constructor.
To avoid the copy you need to pass by reference:
A& A::operator=(const A& other)
Good Read:
What's the difference between passing by reference vs. passing by value?
You seem to be confusing copy-constructors with copy-assignment operators. The implicitly generated copy-constructor will copy-construct each of the members:
A::A( A const& source )
: a( source.a )
, b( source.b )
{}
The implicitly generated copy-assignment operator will copy-assign each of the members:
A& A::operator =( A const& source )
{
a = source.a;
b = source.b;
return *this;
}
The copy-assignment operator as you defined it in your question takes an A by copy, so the copy-constructor will be called to create the argument passed to operator=. Note that the copy may be elided under certain circumstances.
Your class provides operator=. Per the rule of three (as #AlokSave says), you should then provide the copy constructor and destructor as well.
The question is, if you're happy with the default-supplied copy constructor, why aren't you happy with the default-supplied copy assignment operator? And if you are, just don't declare operator= and let the compiler generate the entire "rule of three" for you.
A::A(const A& other) != A& A::operator=(const A other)
Related
Assuming i have this code:
class A {
public:
int x;
A(){}
A(const A& a){} //copy constructor
operator= (const A &a){...}
};
class B {
public:
A a;
B(){}
};
int main() {
B b;
B c = b; //shallow copy
B d;
d = b; //shallow assignment
}
Will the shallow copy\assignment call member A a's copy constructor\assignment operator overloading?
Or shortly does shallow copy perform member objects' user-made copy constructor & assignment operator or a shallow one as well?
The term "shallow copy" is used to describe copies where, after a "shallow copy", the two objects internally reference the same object in some way. As such, manipulating one object may conceptually manipulate a value visible through the other.
Unless the value of the int stored in A is a reference to an object somewhere, nothing in A or B references an object. Therefore, implicitly-defined copies of such objects are not "shallow" (or "deep"). That qualification simply doesn't apply to objects that aren't referencing other objects.
The implicitly defined copy constructor/assignment will perform a member-wise copy of each subobject. So long as those subobjects have copy constructors/assignment operators, they will be called by the implicitly defined versions.
Then the answer is yes, the copy constructor will be called, but the assignment operator will not.
The copy constructor will be called because the defaulted copy constructor is called, but the assignment operator is not. The defaulted assignment operator will call the defaulted copy constructor, and the defaulted copy constructor will call the copy constructor of the base class, but the defaulted assignment operator is not called.
The reason is simple: the defaulted assignment operator is not called because the defaulted assignment operator is declared "A& operator=(const A& a)".
The above is a case in which the calling convention (the "= default" is a member function calling convention) is used.
http://en.cppreference.com/w/cpp/language/rule_of_three
I have begun with c++11 a couple of months ago
and have watched the rule of five.
So.. I started putting copy constructor/copy assignment operator/move constructor/move assignment operator with default keyword on every class having virtual destructor.
because the rule told me that if you declare explicit destructor then your class doesn't have its implicit move constructor and move assignment operator anymore.
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
But It works well! What happend??
class Interface {
public:
virtual ~Interface() = default; // implicit destructor
};
class ImplA : public Interface {
public:
virtual ~ImplA() = default; // implicit destructor
};
ImplA first;
ImplA second(first); // copy constructor, OK. understood it.
ImplA third(std::move(first)); // move constructor, it's OK. Why?
second = first; // copy assignment, OK. understood it.
second = std::move(first); // move assignment, it's also OK. Why?
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
Because the operations required could be performed via copy constructor and copy assignment operator. Interface still has copy constructor and copy assignment operator which are implcitly declared. And rvalues are always possible to be bound to const Interface&.
More precisely, even without move constructor and move assignment operator provided, Interface is still MoveConstructible,
A class does not have to implement a move constructor to satisfy this
type requirement: a copy constructor that takes a const T& argument
can bind rvalue expressions.
and MoveAssignable.
The type does not have to implement move assignment operator in order
to satisfy this type requirement: a copy assignment operator that
takes its parameter by value or as a const Type&, will bind to rvalue
argument.
BTW: If you make the move constructor and move assignment operator delete explicitly then both copy and move operation would fail. Using with an rvalue expression the explicitly deleted overload will be selected and then fails. Using with an lvalue expression would fail too because copy constructor and copy assignment operator are implicitly declared as deleted because of the declaration of move constructor or move assignment operator.
Let's assume I have class with no explicit copy constructor. Is it possible to forbid operation of assigning or copying objects for this class? For example:
class A
{
// data, methods, but no copy constructor and no overloaded assignment operator
};
A object1;
A object2;
object1 = object2; // make compiler error here
A object3 = object1; // or here
You could mark the copy-constructor and copy-assignment operator as deleted:
class A
{
public:
...
A(const A&) = delete;
A& operator=(const A&) = delete;
};
If your compiler doesn't support C++11 features like this, just make the functions private.
Try this
private:
A(A const&); //Don't implement it
A& operator=(A const&);//Don't implement it
or with C++ 11
A(A const&) = delete;
A& operator=(A const&) = delete;
Let's assume I have class with no explicit copy constructor. Is it possible to forbid operation of assigning or copying objects for this class?
Derive it from boost::noncopyable, a base class that is non-copyable, or add a non-static data member that is non-copyable.
If you dont have explicit copy constructor. compiler will create a default one for you.
To forbid copying make copy constructor private.
To forbid assignment make assignment operator private
I also can declare copy constructor or assignment operator without definition. When I call either of them I get linker error.
The implicit copy constructor and assignment operator can only be called if the compiler can generate them. They (conceptually, at least) copy the base class, and then perform memberwise copy of all members. If either of those operations cannot be performed, no implicit copy constructor or assignment operator is generated.
Therefore, you can inhibit these operations by deriving from a non-copyable base class or by including a (non-static) member of a non-copyable type.
As a coding principle, I think it's clearer to explicitly declare the operations as deleted (or private, pre-C++11) members, rather than relying on the presence of a non-copyable member or base class. I'll make an exception if the member/base is named to convey that intent (e.g. boost::noncopyable).
Your question has two part:
First is Explicit constructor, the purpose of explicit constructor is to avoid the implicit construction. By implicit construction I mean
struct C {
int a;
C(int p):a(p) {}
~C(){std::cout<<"Destructor for "<<a<<'\n';}
};
int main() {
C c1 = 142; // implicit-initialization, calls C::C(42)
C c2{12}; //
return 0;
}
But if we make constructor explicit as
explicit C(int a);
Then following code will not compile.
C c1 = 142; // would not compile
This was about the explicit constructor.
Second part is avoiding copy and assignment. So, for that you have two options
As suggested by others,use boost::noncopyable
Remember "The rule of three/five/zero"
http://en.cppreference.com/w/cpp/language/rule_of_three, make your
copy ctor, move ctor & assignment operator as deleted.
The Standard in section 12.8/7 says:
If the class definition does not explicitly declare a copy
constructor, one is declared implicitly. If the class definition
declares a move constructor or move assignment operator, the
implicitly declared copy constructor is defined as deleted; otherwise,
it is defined as defaulted (8.4). The latter case is deprecated if the
class has a user-declared copy assignment operator or a user-declared
destructor. Thus, for the class definition
struct X {
X(const X&, int);
};
a copy constructor is implicitly-declared. If the user-declared
constructor is later defined as
X::X(const X& x, int i =0) { /∗ ... ∗/ }
I can't get the point of that The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. In the example the Standard neither provides a user-declared copy assignment operator nor a destructor. What will happen if we declare a destructor or a copy assignment operator? I've tried to do that as follows:
struct A
{
~A(){ };
};
A::A(const A&){ }; //error
int main(){ }
DEMO
but in the example we still have the implicitly-declared copy constructor. What does that rule actual mean?
I thought that if we write the following:
struct A
{
A(){ };
A(const A&&){ };
~A(){ };
};
A a;
A t = a; //error: call to implicitly-deleted copy constructor of 'A'
int main()
{
}
DEMO
the copy-constructor won't explicitly deleted. But thats's not the case.
This deprecation basically incorporates the Rule of Three (Five). If a user-declared copy assignment operator or destructor is provided, the fact that the copy constructor is defined as defaulted (and not as deleted) is deprecated. That should prevent you from depending upon such an implicitly declared copy constructor in future.
In the example the Standard provides neither copy assignment nor
destructor are user-decalred.
The example has nothing to do with the deprecation.
I've tryied to do that as follows: […] but in the example we still have the impliclty-declared copy
constructor.
You cannot define an implicitly declared copy constructor - because it's already defined, by = default (no pun intended). You would have to declare it yourself first.
I thought that If we wirte the following: […] the copy-constructor won't explicitly deleted. But it's not true.
You quoted the rule that explicitly specifies that the copy constructor will be implicitly defined as deleted if a move constructor is declared:
If the class definition declares a move constructor or move
assignment operator, the implicitly declared copy constructor is
defined as deleted;
Clearly,
A(const A&&){ }
Is a move constructor according to [class.copy]/3. If you removed this move constructor then your example compiles, although it uses said deprecated feature.
Deprecated normally means that something will work, but that it is frowned upon and may not work in the future. I think the standard is saying that if you create a user-declared copy assignment operator or a user-declared destructor it will still create a default copy constructor (if you haven't) - but it may not in the future. So they want you to create your own copy constructor now, if you have one of the other two, and in the future they may force you to.
My current implementation uses lots of copy constructors with this syntax
MyClass::Myclass(Myclass* my_class)
Is it really (functionnaly) different from
MyClass::MyClass(const MyClass& my_class)
and why?
I was adviced that first solution was not a true copy constructor. However, making the change implies quite a lot of refactoring.
Thanks!!!
It's different in the sense that the first isn't a copy constructor, but a conversion constructor. It converts from a MyClass* to a MyClass.
By definition, a copy-constructor has one of the following signatures:
MyClass(MyClass& my_class)
MyClass(const MyClass& my_class)
//....
//combination of cv-qualifiers and other arguments that have default values
12.8. Copying class objects
2) A non-template constructor for class X is a copy constructor if its
first parameter is of type X&, const X&, volatile X& or const volatile
X&, and either there are no other parameters or else all other
parameters have default arguments (8.3.6).113) [ Example: X::X(const
X&) and X::X(X&,int=1) are copy constructors.
EDIT: you seem to be confusing the two.
Say you have:
struct A
{
A();
A(A* other);
A(const A& other);
};
A a; //uses default constructor
A b(a); //uses copy constructor
A c(&a); //uses conversion constructor
They serve different purposes alltogether.
The first version is not a copy constructor. Simple as that. It's just another constructor.
A copy constructor for a class X must have signature (X &, ...) or (X const &, ...) or (X volatile &, ...) or (X const volatile &, ...), where all arguments but the first have default values if they are present (and it must not be a template).
That said, you should think very carefully about why you're violating the Rule of Zero: Most well-designed classes shouldn't have any user-defined copy-constructor, copy-assignment operator or destructor at all, and instead rely on well-designed members. The fact that your current constructor takes a pointer makes me wonder if your code behaves correctly for something like MyClass x = y; — worth checking.
Certain language constructs call for a copy constructor:
passing by value
returning by value
copy-style initialization (although the copy is often elided in that case)
If the language calls for a copy, and you have provided a copy constructor, then it can be used (assuming the cv-qualifications are OK, of course).
Since you have not provided a copy constructor, you will get the compiler-generated copy constructor instead. This works by copying each data member, even if that's not the right thing to do for your class. For example if your not-a-copy-constructor explicitly does any deep copies or allocates resources, then you need to suppress the compiler-generated copy.
If the compiler-generated copy works for your class, then your not-a-copy-constructor is mostly harmless. I don't think it's a particularly good idea, though:
void some_function(const MyClass &foo);
MyClass *ptr = new MyClass();
const MyClass *ptr2 = ptr;
some_function(ptr); // compiles, but copies *ptr and uses the copy
MyClass bar(ptr2); // doesn't compile -- requires pointer-to-non-const
Even assuming that the compiler-generated copy is no good for your class, making the necessary change need not require a lot of refactoring. Suppose that your not-a-constructor doesn't actually modify the object pointed to by its argument, so after fixing the signature you have:
MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
// do stuff here
}
You need:
MyClass::MyClass(const MyClass& my_class) {
do_stuff(my_class);
}
MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
do_stuff(*my_class);
}
MyClass::do_stuff(const MyClass& my_class) {
// do stuff here
}
You also need to copy any initializer list from the old constructor to the new one, and modify it for the fact that my_class isn't a pointer in the new one.
Removing the old constructor might require a lot of refactoring, since you have to edit any code that uses it. You don't have to remove the old constructor in order to fix any problems with the default copy constructor, though.
The first example is not a copy constructor. This means that when you provide it, the compiler still provides you with a default copy constructor with signature equivalent to
MyClass(const MyClass& my_class);
If you are doing something special with your constructor, and the compiler provided copy constructor does not follow that logic, you should either implement a copy constructor or find a way to disable it.
Why would I want to use a copy constructor instead of a conversion constructor?
It can be problematic if you give MyClass objects to some code that expect your copy-constructor to be valid.
This is the case for STL containers. For instance, if you use a std::vector<MyClass>, you must be aware that vectors are allowed to move elements around for reallocation using their copy constructors.
The default constructor provided by the compiler will perform a shallow copy, calling copy constructors of every attributes, making simple copies for base type like pointers. If you want some form of deep copy you will have to properly rewrite the copy constructor of MyClass