Could somebody explain me the difference between copying and assignment?
SomeClass a;
SomeClass b = a; // assignment
SomeClass c(a); // assignment
b = c; // copying
but what is the difference, why there are two different constructions in the language?
Initialization only happens once, when the object is created. If by copying you mean calling the copy constructor, than copying is a form of initialization. Assignment can happen any number of times.
Now, on to your example, all of those are wrong:
SomeClass a();
This declares a method called a which takes no parameters and returns an object SomeClass.
SomeClass b = a; // actually copy constructor & initialization of b
SomeClass c(a); // same
If a were a SomeClass object, these two would be initialization, and it calls the copy constructor - SomeClass::SomeClass(const SomeClass&). They are equivalent.
b = c; // assignment
If c is a SomeClass object, this is assignment. It callse SomeClass::operator =(const SomeClass&).
This is initialization (but it calls the copy constructor):
SomeClass b = a;
So is this:
SomeClass c(a);
This is assignment:
b = c;
Oh, and this isn't an initialization:
SomeClass a();
Copying is for initializing new objects by copying the contents of existing ones, assignment is for overwriting existing objects with the contents of other objects - the two are very different things. In particular, this
SomeClass a;
SomeClass b = a;
is copy initialization - you're copying a to create a new SomeClass called b using syntax of the form
T x = y;
This has the effect of invoking SomeClass's copy constructor (assuming there is one and it's accessible). The compiler-generated default copy constructor would do a memberwise copy of a; you can replace it with your own as needed, e.g.
SomeClass(const SomeClass& rhs)
: x(rhs.x)
{}
(Note that this is a very boring example, as it just does what the default memberwise copy constructor might.)
Moving on, this
SomeClass c(a);
is direct initialization using the copy constructor. It will generally have the same effect as the above, but this is worth a read:
http://www.gotw.ca/gotw/036.htm
Also, see here:
http://www.gotw.ca/gotw/001.htm
Your final case, namely
b = c;
is assignment. The semantics of this should generally be to overwrite b with the contents of c (although some things, such as std::auto_ptr, have strange assignment semantics, so watch out). To implement your own assignment operator, you write something like this (note that this is a very boring example, as it just does what the default memberwise assignment operator might):
SomeClass& operator=(const SomeClass& rhs)
{
x = rhs.x;
return *this;
}
In practice, however, you have to be careful about exception safety in situations like this, which leads to things like the popular copy-and-swap idiom for implementing assignment operators. See here:
http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap
Initializations initialize a previously uninitialized object. Assignments, on the other hand, overwrite an already initialized object and may have to destroy existing state. These are different operations; while they usually have the same outcome for the object on the LHS, they are not semantically equivalent.
Related
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).
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.
The rule-of-three is well known and says that if one has to define a destructor, so one has most probably to define a copy constructor and an assignment operator.
However, recently in some code, I stumbled upon a "rule-of-two": Only the destructor and the copy constructor were defined and the assign operator was left for compiler to define. My first thought was "this must be an error", but now I'm not that sure, because all compilers (gcc, msvs, intel) produced assignment operator which called the copy constructor.
Simplified, the class looks as follows:
struct A{
size_t size;
int *p;
A(size_t s): size(s), p(new int[size]){}
A(const A&a): size(a.size), p(new int[size]){
std::copy(a.p, a.p+a.size, p);
std::cout<<"copy constructor called\n";
}
~A(){
delete[] p;
}
};
And used like this:
int main(){
A a(2);
a.p[0]=42.0;
A b=a;
std::cout<<"first: "<<b.p[0]<<"\n";
}
produces the following output:
copy constructor called
first: 42
My question: It is guarantied, that the compiler defined assignment operator will call the copy constructor, or it is only a lucky coincidence, that all compilers do it that way?
Edit: It's true, I confused initialization and assignment! Replacing A b=a; by A b(0); b=aleads as expected to a double-free-error.
It's you who misunderstands what's happening, there is no assignment at all going on, only construction and initialization.
When you do
A b = a;
there's no assignment, only initialization. More precisely copy initialization. It's the same as writing
A b(a);
Initialization create a new object:
A a; // initialization
A b(a); // initialization
A c = a; // initialization
Assignment modifies an existing object:
A a;
a = 3; // assignment
In the code example, as various comments have said, there is no assignment being done; all of the examples are initializations, so the compiler-generated assignment operator is not used.
In trying to understand this answer, it seems that new can be classified as a "copy constructor" and delete sometimes as a "trivial destructor".
I can find next to nothing (that I can quickly grasp) on "trivial assignment" except that it is "trivial if it is implicitly declared, if its class has no virtual member functions or virtual base classes, and if its direct base classes and embedded objects have a trivial assignment operator".
I found a question on yahoo about implicit declaration, but to my surprise, it did not answer.
My brain hurts after reading about virtual member functions.
Besides, I'm a monkey-see-monkey-do programmer, so the only way I'm going to get this is to see it in action. Please explain with respect to the above definition of "trivial" by using the example provided in the first answer, that std::string has a trivial assignment operator by using new or delete or for a less apparent reason.
New can use a copy constructor, and delete uses a destructor. The copy constructor or destructor may be trivial.
That being said, there is a STRONG chance that you will not need to worry about whether a constructor/destructor is trivial for a long time.
new calls a constructor to construct the object. If the one argument to the constructor of type T is an instance of T that is a copy constructor: you are trying to construct an instance of one object from another
class Foo
{
public:
Foo(int x) // not a copy constructor
: mX(x)
{ }
Foo(const Foo& inOther) // copy constructor
: mX(inOther.mX)
{ }
private:
int mX;
};
class Bar
{
public:
Bar(int x)
: mX(x)
{ }
// no copy constructor specified.. C++ will build an implicit one for you
private:
int mX;
}
};
Foo a(1); // uses the first constructor (not a copy)
Foo b(a); // uses a copy constructor
Foo c = a; // copy constructor
Foo* d = new Foo(1); // construct a new instance of Foo (not a copy)
Foo* e = new Foo(a); // copy
Bar f(1); // normal constructor
Bar g(f); // IMPLICIT copy constructor
If your class does not have a copy constructor, like Bar, C++ usually provides you one (always provides you one unless you have an explicit constructor or delete the copy constructor with a C++11 keyword). This copy constructor is very straightforward: it copies each member of your class.
A trivial copy constructor is special. A trivial copy constructor can only be created when the copy constructor is implicitly created for you by the compiler and:
All members of your class are trivially copyable
You do not have any virtual methods or virtual base classes
All of your base classes are trivially copyable.
If you specify a constructor in your class, it is not trivial, by definition. Foo does not have a trivial copy constructor because it is user defined. Bar has an implicit copy constructor because it is not user defined. The implicit copy constructor IS trivial, because copying mX is trivial (copying ints is trivial).
Similar rules go for destructors. A trivial destructor follows the same rules, and delete
WHat does it do for you? The spec lists a few key behaviors about trivial constructors/destructors. In particular, there's a list of things you can do if you have a trivial constructor and destructor that are illegal otherwise. However, they are all very nuanced, and unimportant to 99.9% of C++ code development. They all deal with situations where you can get away with not constructing or destructing an object.
For example, if I have a union:
union MyUnion {
int x;
ClassA y;
ClassB z;
}
If y and z have trivial constructors and destructors, C+ will write a copy constructor for that union for me. If one of them has a non-trivial constructor/destructor, I have to write the copy constructor for the union myself.
Another thing you can do is fast destruction of an array. Usually, when you delete an array, you have to make sure to call the destructor on every item. If you can prove that the destructor of each element is trivial, then you are allowed to skip destroying the elements, and just free the memory. std::vector does this under the hood (so you don't have to)
I have a class which does not have copy constructor or operator= overloaded.
The code is pretty big but the issue is around this pseudo-code:
ClassA object1(x,y);
object1.add(z)
myVector.push_back(object1);
//Now when I retrieve from myVector and do add it
// apparently creates another object
myVector.at(index).add(z1);
Like I said it is pseudo-code. I hope it make sense to experts out there!
So, ClassA looks like this (of course not all data members included)
Class ClassA {
private:
int x;
string y;
ClassB b;
vector<int> i;
public:
int z;
}
Since ClassB b is a new data member for this release, is the need of copy constructor now become a must?
Thanks again all of you for responding.
Class ClassB {
private:
vector<ClassC*> c;
Class D
}
Class ClassC {
private:
vector<ClassE*> e;
}
Class ClassD{
private:
vector<ClassF*> f;
}
Then ClassE and ClassF have basic types like int and string.
The new object isn't being created when you retrieve the object using
at(); at() returns a reference to it. The new object is being
created when you do the push_back(). And if you don't have an
accessible copy constructor or assignment operator, you can't put the
object into a vector; officially, it's undefined behavior, but at least
if you use the vector (as you've done here), it will in fact not
compile. Most likely you're getting the compiler generated defaults.
Without seeing the actual object type, it's impossible for us to say
whether they're appropriate; if the object type only contains basic
types and types from the standard library (other than the iostream stuff
and auto_ptr—and the threading stuff if you're using C++11),
then the compiler generated copy constructor and assignment should be
OK. If the class contains pointers to memory you allocate in the
constructor, it almost certainly isn't.
It must create a temporary when retrieving because the value stored is a copy.
I have a class which does not have copy constructor or operator= overloaded.
This does not really matter. Unless you explicitly disable them (declare as private and don't implement in C++03, define as delete in C++11) the compiler will generate one for you.
Now, if you do disable copying of your objects you will realize that you can no longer store them directly in a vector, as the vector will copy the argument internally. You could on the other hand store a (smart) pointer in the container, but this might actually complicate the problem you want solved.
I doubt that it is using a copy constructor, but just plain old struct copy.
myVector.at(index)
returns ClassA in this case, not ClassA &
You should be able to solve this by:
ClassA & refObj = myVector.at(index);
refObj.add(z1);
I put together a little test which had surprising results on Visual Studio.
class Boo {
public:
void add() { a++; }
int a;
};
vector<Boo> v;
Boo b;
b.a = 1;
for (int i=0; i<5; i++) {
v.push_back(b);
}
v[0].add();
v.at(1).add();
Boo & refB = v[2]; refB.add();
refB = v.at(3); refB.add();
Boo & refB2 = v.at(4); refB2.add();
printf("%d %d %d %d %d\n", v[0].a, v[1].a, v[2].a, v[3].a, v[4].a);
Results:
2 2 2 1 2
So the compiler treats:
Boo & refB = v[2]; refB.add();
refB = v.at(3); refB.add();
Differently than:
Boo & refB2 = v.at(4); refB2.add();
But I don't get the original problem (that is, v.at(n).add() is not copying, but passing by reference). Are you sure the following line is copying?
myVector.at(index).add(z1)
Could this be compiler specific? What compiler / OS are you using?
I have a class which does not have copy constructor or operator= overloaded.
In that case, the compiler provides these for you. Quoting the C++ 2003 standard, clause 12.8:
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. … The implicitly-declared copy constructor for a class X will have the form
X::X(const X&) [or] X::X(X&). … The implicitly-defined copy constructor for class X performs a memberwise copy of its subobjects.
and
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. … The implicitly-declared copy assignment operator for a class X will have the form X& X::operator=(const X&) [or] X& X::operator=(X&). … The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects.
The push_back creates a copy as it receives the parameter by value. If you dont want to use a copy constructor define the vector as a vector of pointers to your object, and push a pointer instead.