C++: call copy assignment in copy constructor - c++

OK,I am reading "effective C++" and item 12 says please don't call copy assignment in copy constructor.But after I try to do this, it does work. So I want to ask why, I can't reuse the copy assignment code in copy constructor?

Assume you use copy-assignment operator in copy-constructor. Then you lose the ability to implement copy-and-swap idiom for assignment operator:
struct A
{
A (const A &a)
{
*this = a; // Assignment to a not yet constructed object is not well
}
A &operator=(A a) // Pass by value
{
// ...
}
};
A a1, a2;
a1 = a2; // Infinite recursion!
It's not possible and infinite recursion will occur.

A constructor creates a new object; an assignment operator modifies an existing object. You can't use an assignment operator to create a new object: it doesn't know how to do that, even if it seems to work in simple cases.

Related

Am I calling the constructor or the copy constructor? [duplicate]

I don't understand the difference between assignment constructor and copy constructor in C++. It is like this:
class A {
public:
A() {
cout << "A::A()" << endl;
}
};
// The copy constructor
A a = b;
// The assignment constructor
A c;
c = a;
// Is it right?
I want to know how to allocate memory of the assignment constructor and copy constructor?
A copy constructor is used to initialize a previously uninitialized object from some other object's data.
A(const A& rhs) : data_(rhs.data_) {}
For example:
A aa;
A a = aa; //copy constructor
An assignment operator is used to replace the data of a previously initialized object with some other object's data.
A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}
For example:
A aa;
A a;
a = aa; // assignment operator
You could replace copy construction by default construction plus assignment, but that would be less efficient.
(As a side note: My implementations above are exactly the ones the compiler grants you for free, so it would not make much sense to implement them manually. If you have one of these two, it's likely that you are manually managing some resource. In that case, per The Rule of Three, you'll very likely also need the other one plus a destructor.)
The difference between the copy constructor and the assignment operator causes a lot of confusion for new programmers, but it’s really not all that difficult. Summarizing:
If a new object has to be created before the copying can occur, the copy constructor is used.
If a new object does not have to be created before the copying can occur, the assignment operator is used.
Example for assignment operator:
Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator
Example for copy constructor:
Base obj1(5);
Base obj2 = obj1; //calls copy constructor
The first is copy initialization, the second is just assignment. There's no such thing as assignment constructor.
A aa=bb;
uses the compiler-generated copy constructor.
A cc;
cc=aa;
uses the default constructor to construct cc, and then the *assignment operator** (operator =) on an already existing object.
I want know how to allocate memory of the assignment constructor and copy constructor?
IDK what you mean by allocate memory in this case, but if you want to see what happens, you can:
class A
{
public :
A(){ cout<<"default constructor"<<endl;};
A(const A& other){ cout<<"copy constructor"<<endl;};
A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};
I also recommend you take a look at:
Why is copy constructor called instead of conversion constructor?
What is The Rule of Three?
In a simple words,
Copy constructor is called when a new object is created from an existing object, as a copy of the existing object.
And assignment operator is called when an already initialized object is assigned a new value from another existing object.
Example-
t2 = t1; // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1; // calls copy constructor, same as "Test t3(t1);"
What #Luchian Grigore Said is implemented like this
class A
{
public :
int a;
A(){ cout<<"default constructor"<<endl;};
A(const A& other){ cout<<"copy constructor"<<endl;};
A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};
void main()
{
A sampleObj; //Calls default constructor
sampleObj.a = 10;
A copyConsObj = sampleObj; //Initializing calls copy constructor
A assignOpObj; //Calls default constrcutor
assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}
OUTPUT
default constructor
copy constructor
default constructor
assignment operator
the difference between a copy constructor and an assignment constructor is:
In case of a copy constructor it creates a new object.(<classname> <o1>=<o2>)
In case of an assignment constructor it will not create any object means it apply on already created objects(<o1>=<o2>).
And the basic functionalities in both are same, they will copy the data from o2 to o1 member-by-member.
I want to add one more point on this topic.
"The operator function of assignment operator should be written only as a member function of the class." We can't make it as friend function unlike other binary or unary operator.
Something to add about copy constructor:
When passing an object by value, it will use copy constructor
When an object is returned from a function by value, it will use copy constructor
When initializing an object using the values of another object(as the example you give).

What happens behind the scenes when manually calling a constructor in C++?

This is an educational question, I am interested in what happens behind the scenes when I do:
SomeClass x(arg1, arg2, arg3); // An instance of SomeClass is constructed.
x = SomeClass(arg4, arg5, arg6); // Intent is to create a new instance.
SomeClass does not have operator= implemented.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens? And when is it a good idea?
This can best be explained with the help of a small example:
Live on Coliru
struct A {
A(int a) { cout << "A::ctor\n"; } //ctor
A(const A& a) { cout << "A::copy\n"; } //copy ctor
A& operator=(const A& a) { cout << "A::operator=\n"; } //copy assign
};
int main()
{
A a(2); //calls constructor
a = A(10); //calls constructor first, then copy assignment
}
Output:
A::ctor
A::ctor
A::operator
The above is pretty self explanatory. For the first, only the constructor gets called. For the second, first the constructor is called and then copy assignment.
SomeClass does not have operator= implemented.
That doesn't matter because the compiler can generate one for you. If you explicitly delete it, then the above code will not compile. However, if you have a move constructor defined then that will be used:
(I highly recommend you read The rule of three/five/zero and understand it. It is among the top 5 things in C++ that you should know.)
A& operator=(const A& a) = delete; //copy assign deleted
A& operator=(A&& other) { cout << "move assigned\n"; } //move assign available
Now you maybe wondering what will happen if both copy and move assign are available. Lets see:
A a(2); //ctor
a = A(10); //ctor + move assign
A b(3); //ctor
b = a; // copy assign only
a = std::move(b); // move assign
For a = A(10) move assign is invoked because A(10) is an rvalue of the same type as what is on the left hand side of the =.
For the last case a = std::move(b);, we explicitly cast b to an rvalue (yes that's what std::move() does). Since it's an rvalue now, move assignment is invoked.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens?
First the temporary is created: A(10). Space will of course be allocated for it.
It's result is then assigned to a, so previous values in a get overwritten
destructor for the temporary will be called
And when is it a good idea?
It is a good idea when you need it, it depends on your usecase. Generally I would recommend that don't copy assign unnecessarily.
Second line is call of constructor followed by call to assignment operator. Assigment default to shallow copy of non-static members into existing storage.
If you defined something that prevented compiler to create default operator=, i.e. you defined move constructor or move assignment, no assignment is possible unless you declared your own (why it is so surprising?) If default shallow copy is fine, you can write following declaration:
SomeClass& operator(const SomeClass&) = default;
= default provides mechanism to declare "default" behavior of special functions.
Now there is move assignment and in such case one would be preferred if it declared in given context. But it won't be declared by compiler if user provided destructor or copy\move constructor\assignment operator.
SomeClass& operator(SomeClass&&) = default;
Difference between two assignments exists only for class-types where "move" semantics may include transfer of ownership. For trivial types and primitive types it's a simple copy.
Compiler allowed to elide some actions including creation of storage for temporary object, so resulting code may actually write new values directly into x storage, provided that such elision won't change program behavior.

constructor and the assignment operator

Can I write a copy constructor through the assignment operator? Like this:
A::A(const A * a) {
*this = a;
}
A &A::operator=(const A * a) {
delete str;
str = new char[strlen(a->str)+1];
strcpy(str, a->str);
return *this;
}
Still want to clarify whether if I do A * a in the above example, because samples from different sites A & a. C This pops up a question that should return the assignment operator:
A &A::operator=(const A * a)
or
A * A::operator=(const A * a)
General question: Is my code right above?
The best solution is to make str be a std::string and then you don't need to write your own copy constructor OR copy assignment operator.
But let's say you have to write your own for non-obvious reasons you can't share with us.
In that case, a typical approach to provide some exception safety is to implement a nothrow swap function, and then implement copy assignment in terms of copy construction + swap (the opposite of what you're proposing, but provides much better exception safety for the copy assignment)
Both of them have different signature:
A::A(const A &a);
A &A::operator=(const A &a);
What you are writing is not copy constructor nor assignment operator.
Look for copy-and-swap idiom, this is what allows you to write copy assignment in terms or copy construction.

Why to use copy constructor C++

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.

Why assignment operator is used for deep copy and who calls it

During deep copy we are writing overloaded copy constructor and assignment operator.
May i know why we have to write the overloaded assignment operator because we doing the same in overloaded copy constructor(except some check and return this).
Who is calling assignment operator
Follow the Rule of Three:
If you need to write an copy constructor for your class, You also should write the Copy assignment operator and Destructor.
Copy Assignment operator and Copy Constructor both are called Copying functions. They basically help in getting a new copy of an object from an existing object. They both are separate entities invoked in different scenarios. So, just as in case of Copy constructor you ensure that you make deep copies of all pointer members and not just shallow copies, same would applies for copy assignment operator.
An Code Example:
class MyClass obj1, obj2;
class MyClass obj3(obj1); //Calls Copy Constructor
obj1 = obj2; //Calls Copy Assignment Operator
The assignment operator is used if you do this:
MyType my1, my2;
my1 = my2; // same as: my1.operator=(my2);
The copy constructor and the assignment operator usually have very similar code, but if done properly (initializer lists) should be coded differently, used differently, and perform differently.
The copy constructor should use initializer lists. This is used for creating a new vector object that is the same as one already existing.
vector::vector(const vector& b)
:size(b.size),
capacity(b.capacity),
data(new TYPE[size])
{
//there should be minimal code here
//I'm skipping copying the data, because doing it right
//is hard and beside the point
}
vector seven;
seven.push_back(7);
vector seven_copy(seven); //make a new one, same as old
The assignment operator is probably exactly what you have. This is used to reassign an already existing vector object to be the same as one already existing
vector& vector::operator=(const vector& b)
{
//carefully written so self assignment doesn't crash.
TYPE* temp = new TYPE[b.size];
//I'm skipping copying the data, because doing it right
//is hard and beside the point
delete [] data;
//all exceptions that can be thrown, have, so it's safe to modify members now
data = temp;
size = b.size;
capacity = b.capacity;
return *this;
}
vector nine;
nine.push_back(9);
nine = seven; //make an old one the same as another old
It should be noted that the move constructor and move assignment may look vaguely similar, but should probably be different as well.
vector::vector(vector&& b)
:size(b.size)
capacity(b.capacity)
data(b.data) //different!
{
b.data = nullptr;
}
vector& operator=(vector&& b)
{
//since b.data is tied to b.size and b.capacity, it's safest to just swap
//so if someone calls b.push_back() after, it's all still safe.
std::swap(size, b.size);
std::swap(capacity, b.capacity);
std::data(data, b.data);
return *this;
}