Why we need to define the operator or copy constructors as these are system supplied default constructors?
Kindly explain this with examples
You need to provide them when you need different behaviour than what the default, compiler provided, functions implement.
The default copy constructor copies all members by value. The default assignment operator assigns all members by value.
In a lot of cases this is just what you want so there is no need to provide your own implementations. But that is not always the case.
Consider this contrived example:
struct Broken {
Broken() : i(42), p(new int) { }
~Broken() { delete p; }
int i;
Int* p;
};
It will get the default compiler generated copy ctor and operator= but in this case they don't do what you want - consider this:
int main()
{
Broken b1;
Broken b2 = b1;
} // you'll probably crash here with a double free
What happens is that b1 stores 42 in its i member, then allocates a new int on the heap and stores the address in its p member (let's say the address is 0x1234).
Then we construct b2 from b1 and the default copy constructor happily assigns b2.i to be 42 - this is fine. It also assigns b2.p to have the value 0x1234 - this is not what you want. Now both objects hold a pointer to the same memory and both their destructors will attempt to delete it.
Thus, when b2 goes out of scope at the end of main it disposes of the memory - so far so good - but then b1 also goes out of scope and tries to release the already freed memory and your program is now broken.
In this case you would want to provide your own operator= and copy ctor that don't naively copy the value of the pointer, but instead make a deep copy of whatever the pointer points to and stores that in a new chunk of memory that is distinct from the original, so that both objects have their own unique copy.
There are many other examples but this was the simplest I could come up with.
Related
Why do we need special algorithms to write to uninitialized (but allocated) memory? Won't the normal modifying algorithms do? Or does uninitialized memory mean something different from what the name itself conveys?
Take std::copy and std::uninitialized_copy for a range of std::strings.
Regular copy will assume there already exists a string there. The copy assignment operator of string will try to use any existing space in the string if possible for the copy.
However, if there wasn't already a string there, as in the case of an uninitialized memory, the copy assignment operator will access garbage memory and behavior is undefined.
Uninitialized copy on the other hand will create the string there instead of assigning to it, so it can be used in a memory that does not already have a string in it.
Essentially, the regular versions will have a *it = value; in them, and uninitialized versions will have something like a new (&(*it)) T(value);.
It is essentially about the object lifecycle.
After memory is allocated, it must be initialized by running the class' constructor. When the object is finished with, the class' destructor must be run.
The standard algorithms assume they are always accessing initialized memory and so objects can be created, copied, swapped and moved and deleted etc... based on that assumption.
When dealing with uninitialized memory however, the algorithms have to make sure they do not run a destructor on memory that was never initialized with the constructor. They have to avoid moving and swapping with non-existent objects by initializing the memory first when needed etc...
They have to deal with the extra step in the object lifecycle (initialization) that is unnecessary with already initialized memory.
It's the difference between construction and assignment:
struct foo { /* whatever */ };
foo f;
unsigned char buf[sizeof foo];
foo *foo_ptr = (foo*) buf;
*foo_ptr = f; // undefined behavior; *foo_ptr does not point at a valid object
new (foo_ptr) foo; // okay; initializes raw memory
*foo_ptr = f; // okay; assignment to an existing object
The assignment operator copies one object to another member-wise. If you do not overload the assignment operator, it performs the bitwise copy.
When the bitwise assignment is performed both the object shares the same memory location and changes in one object reflect in another object.
This concept and my code goes contrary. Can someone please explain me why..
#include<bits/stdc++.h>
using namespace std;
class A
{
public:
int x;
};
int main()
{
A a1,a2;
a1.x=5;
a2.x=5;
a2=a1;
a1.x=10;
cout<<a1.x<<" "<<a2.x;
return 0;
}
When the bitwise assignment is performed both the object shares the same memory location and changes in one object reflect in another object.
This is incorrect. Bitwise copy assignment does not lead to objects sharing the same memory. It's a separate copy, so a2 and a1 are in fact in different memory location.
This concept and my code goes contrary.
You probably got mixed up with the case where copy assignment is done with a pointer member variable. In that case, indeed the default bitwise assignment would lead to objects having pointers pointing to the same memory, and requires deep copy assignment instead (of the default assignment).
Your current code does not have any pointer member though, so such deep copy is not required.
If you use a pointer in your class since two object the origin and assigned object access to same memory address so if you change this memory location the modification is visible for two objects.
#include<bits/stdc++.h>
using namespace std;
class A
{
public:
int x;
int *y;
};
int main()
{
A a1,a2;
a1.x=5;
a1.y = new int(7);
a2.x=5;
a2=a1;
a1.x=10;
*a2.y = 9;
cout<<a1.x<<" "<<a2.x;
cout<<*a1.y<<" "<<*a2.y; // the output is 9 9/ because both object access two same memory address
return 0;
}
The values of a1 are copied in a2. If your class had pointer, then the pointer value, ie the address would be copied the same, which would mean that had be sharing same address and then changing value in one is changing value in the other as well.
When the bitwise assignment is performed both the object shares the same memory location and changes in one object reflect in another object.
is wrong. Copying is copying. This means data in the memory location for source object is copied to another memory location for destination object. No memory location sharing is done.
You understanding of default assignment operators is incorrect, default assignment operators use a copying method known as a member-wise copy. I will not share the memory.
Since, you misunderstood the concept, there is an expected behavior.
so I have an exam soon, and glancing through my notes, the teacher says that a shallow copy is defined as a bit by bit copy. I know all about shallow and deep copies, yet I have no idea what bit by bit copy is supposed to mean. Isn't all computer data stored as bits? Could this definition imply that during a shallow copy, a bitstream is implemented when copying the data? Anybody know stuff about this "bit by bit" terminology? Thanks
Say you have two variables MyObj a, b;. If a = b performs a shallow copy, then the bits in the variable b will now be the same as the bits in the variable a. In particular, if MyObj contains any pointers or references, they are the same in both a and b. The objects which are pointed or referred to are not copied.
Bit by bit copy / Shallow copy
Take for example a pointer pointing to a chunk of data:
int* my_ints = new int[1000];
my_ints point to the start of an area of memory which spans a thousand ints.
When you do
int* his_ints = my_ints;
the value of my_ints is copied to his_ints, i.e. the bits of my_ints is copied to his_ints. This means that his_ints also points to the start of the same area of memory which my_ints also points. Therefore by doing
his_ints[0] = 42;
my_ints[0] will also be 42 because they both point to the same data. That is what your professor is most probably referred to as "bit by bit" copying, which is also commonly called as "shallow copy". This is mostly encountered when copying pointers and references (you can't technically copy references, but you can bind a reference to a variable bound to another reference).
Deep copy
Now, you may not want to have the bit by bit copy behavior. For example, if you want a copy and you want to modify that copy without modifying the source. For this, you do a deep copy.
int* my_ints = new int[1000];
int* his_ints = new int[1000];
std::copy(my_ints, my_ints + 1000, his_ints);
std::copy there copies the ints in the area of memory pointed to by my_ints into the area of memory pointed to by his_ints. Now if you do
my_ints[0] = 42;
his_ints[0] = 90;
my_ints[0] and his_ints[0] will now have different values, as they now point to their respective and different areas of memory.
How does this matter in C++?
When you have your C++ class, you should properly define its constructor. The one constructor that is relevant with the topic is the copy constructor (note: this also applies to the copy assignment operator). If you only let the compiler generate the default copy constructor, it simply does shallow copies of data, including pointers that may point to areas of memory.
class Example {
public:
int* data;
Example() {
data = new int[1000];
}
Example(const Example&) = default; // Using C++11 default specifier
~Example() {
delete[] data;
}
};
// Example usage
{
Example x;
Example y = x; // Shallow copies x into y
assert(x.data == y.data);
// y's destructor will be called, doing delete[] data.
// x's destructor will be called, doing delete[] data;
// This is problematic, as you are doing delete[] twice on the same data.
}
To solve the problem, you must perform a deep copy of the data. For this to be done, you must define the copy constructor yourself.
Example(const Example& rhs) {
data = new int[1000];
std::copy(data, data + 1000, rhs.data);
}
For more info and better explanation, please see What is The Rule of Three?.
I would define a bit-by-bit copy as the transfer of the information allocated to an object as an unstructured block of memory. In the case of simple structs this is easy to imagine.
What are the contents of the source struct? Are they initialized? What are its relationships to other objects? All unimportant.
In some sense, a bit-by-bit copy is like a shallow copy in that like a shallow copy a bit-by-bit copy will not duplicate related objects, but that's because it doesn't even consider object relationships.
For example C++ defines a trivial copy constructor as
A trivial copy constructor is a constructor that creates a bytewise copy of the object representation of the argument, and performs no other action. Objects with trivial copy constructors can be copied by copying their object representations manually, e.g. with std::memmove. All data types compatible with the C language (POD types) are trivially copyable.
In contrast, shallow copy and its counter-part deep copy exist as a concept precisely because of the question of object relationships.
#include<iostream>
class A{
public :
int a;
};
int main(){
A obj;
obj.a = 5;
A b(obj);
b.a = 6;
std::cout<<obj.a;
return 0;
}
why is the answer returned as 5 , by default copy constructor in C++ returns a shallow copy. Isn't the shallow copy means reference ??
or m i missing something ?
shallow copy means reference ?? or m i missing something ?
You are missing something. Shallow copy means copy. It copies all the members of the object from one to another. It is NOT a reference. The copy created is completely independent of the original
See this excellent tutorial for the difference between shallow and deep copy.
b is a completely separate object from obj. It has its own a independent of obj's.
It sounds like what you have in mind is a reference:
A& b = obj;
After this, both b and obj refer to the same object. Changes made through b would be visible through obj and vice versa.
shallow copy means reference ?? or m i missing something ?
Yes, you're missing something.
Shallow copy doesn't mean reference. Shallow copy means copying the members : if a member is a pointer, then it copies the address, not the content the pointer is pointing to. That means, the pointers in the original object and the so-called copied object point to the same content in memory. That is called shallow copy. Deep copy, on the other hand, doesn't copy the address, it creates a new pointer (in the new object), allocates memory for it, and then copies the content the original pointer points to.
In your case, shallow copy and deep copy make no difference because there are no pointer member(s) in the class. Every member is copied (as usual), and since no member is a pointer, each copied member is a different member in memory. That is, the original object and the copied object are completely different objects in memory. There is absolutely nothing that the two objects share with each other. So when you modify one, it doesn't at all change anything in the other.
Yes, the default copy constructor is a shallow copy. See more here
But, b is completely disjoint from a, so the two things are not related directly.
A b(obj) copies obj information into the newly created object b. Yes it's a shallow copy so b does not actually control what's being assigned to it. What you're probably thinking about is a reference:
A& b = obj;
b.a = 6;
std::cout << obj.a; // 6
I am confused about how to use destructors when I have a std::vector of my class.
So if I create a simple class as follows:
class Test
{
private:
int *big;
public:
Test ()
{
big = new int[10000];
}
~Test ()
{
delete [] big;
}
};
Then in my main function I do the following:
Test tObj = Test();
vector<Test> tVec;
tVec.push_back(tObj);
I get a runtime crash in the destructor of Test when I go out of scope. Why is this and how can I safely free my memory?
The problem is you don't define a copy constructor for Test. So the compiler generates a default copy constructor for you, which just copies the content of the object - in this case the int pointer.
Now, when you push back your object into the vector, it is implicitly copied with the copy constructor. Which results in two objects pointing to the same array of ints! So in the end, two destructors try to delete the same array - BANG.
Whenever you define a class which owns members via pointers*, apart from the destructor you must also define a copy constructor for it. Update: and an assignment operator, for the same reason (thanks #James :-)
Update2: A trivial way to get around all these restrictions is to define a static array instead of the dynamically allocated one:
class Test
{
private:
int big[10000];
// no need for constructors, destructor or assignment operator
};
However, the best practice is to use std::vector<int> instead of an array.
* that is, contains pointers to members with ownership semantics (thanks to #Steve Jessop for clarification)
Your problem is here:
Test tObj = Test();
The Test() creates a temporary Test object, which then gets copied to tObj. At this point, both tObj and the temporary object have big set to point to the array. Then the temporary object gets destroyed, which calls the destructor and destroys the array. So when tObj gets destroyed, it tries to destroy the already-destroyed array again.
Further, when tVec is destroyed, it will destroy its elements, so the already-destroyed array will be destroyed yet again.
You should define a copy constructor and an assignment operator so that when a Test object gets copied, the big array gets copied, or has some sort of reference count so that it doesn't get destroyed until all owners are destroyed.
An easy fix is to define your class like this:
class Test
{
private:
std::vector<int> big;
public:
Test (): big(10000) {}
};
In this case, you wouldn't need to define any destructor, copy constructor, or assignment operator, because the std::vector<> member will take care of everything. (But note that this means 10,000 integers get allocated and copied whenever you copy an instance of Test.)
Without a copy-constructor, the vector will create a flat copy of your object. This leads to two objects of type Test referencing the same array big. The first instance deletes the array when it gets destroyed, and then the second instance try to dereference a deleted pointer, which is undefined behavior.
Test tObj = Test();
This is wrong and should be as it does not create copies:
Test tObj;
This also create a lot of copies:
vector<Test> tVec;
tVec.push_back(tObj);
So if you free one int array, you'll free all the arrays. And the following delete will fail.
What you need is either:
use a copy constructor to have for each class a separate array
Why use a pointer?
class Test
{
private:
int big[10000];
public:
};
This will work fine.