Working of assignment operator while copying objects - c++

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.

Related

System defined Constructors Vs user defined constructors in C++

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.

bit by bit definition (c++ shallow copy)

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.

Local variable deletes memory of another variable when going out of scope [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 9 years ago.
While designing a class that dynamically allocates memory I ran into the following problem regarding memory allocation. I was hoping that some of you might be able to point me in the right direction as to how I should design my class in a better way. My class dynamically allocates memory and therefore also deletes it in its destructor.
In order to illustrate the problem, consider the following silly class declaration:
class testClass{
int* data;
public:
testClass(){
data = new int;
*data = 5;
}
~testClass(){
delete data;
}
};
So far so good. Now suppose that I create one of these objects in main
int main(){
testClass myObject;
return 0;
}
Still no issues of course. However, suppose that I now write a function that takes a testClass object as an input and call this from main.
void doNoting(testClass copyOfMyObject){
//do nothing
}
int main(){
testClass myObject;
doNothing(myObject);
return 0;
}
This time around, the function creates a local variable, copyOfMyObject, that's simply a copy of myObject. Then when the end of that function is reached, that local object automatically has its destructor called which deletes the memory pointed to by its data pointer. However, since this is the same memory pointed to by myObject's data pointer, myObject inadvertently has its memory deleted in the process. My question is: what is a better way to design my class?
When you call doNothing(), it is making a copy of your testClass object, because it is being passed by value. Unfortunately, when this copy is destroyed, it calls the destructor, which deletes the same data used by the original instance of testClass.
You want to learn about "copy constructors", and "passing by reference". That is, you should define a copy constructor for your class so that when a copy is made of an instance, it allocates its own memory for its data member. Also, rather than passing by value, you could pass a pointer or a reference to doNothing(), so that no copy is made.
You should create a copy constructor, that is a constructor of the form:
testClass::testClass(const testClass &o)
{
// appropriate initialization here
}
In your case, "appropriate initialization" might mean allocate a new chunk of memory and copy the memory from the old chunk into the new chunk. Or it may mean doing reference counting. Or whatever.
You should also read more about the Rule of Three right here on StackOverflow!
Here's a guideline from an authority: A class with any of {destructor, assignment operator, copy constructor} generally needs all 3
You need a copy constructor that will make a new allocated int for your data, that will then destruct that, but not affect the original.
Alternately, you can make a private copy constructor that's blank, which effectively disables it, forcing your users to pass by reference, or another non-copying way of doing things.

c++ copy constructor related query

#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

Memory management differences in return by value

I'm trying to follow a tutorial here: regarding overloading operators, and I've found something that's really confused me.
There was a previous question on this very website here where this tutorial was discussed, namely regarding how the variables in the class were preserved because the whole class was passed back by value.
Whilst experimenting with the class definition I toyed with making the integer variables pointers (perhaps not sensible - but just to experiment!) as follows:
class CVector {
int* x;
int* y;
public:
CVector () {};
CVector (int,int);
CVector operator + (CVector);
~CVector ();
};
In the class constructor I allocate memory for the two integers, and in the class deconstructor I delete the allocated memory.
I also tweak the overloaded operator function as follows:
CVector CVector::operator+ (CVector param) {
CVector temp;
*temp.x = *x + *param.x;
*temp.y = *y + *param.y;
return (temp);
}
For the original code, where the class has simple integer variables the return by value of the entire class completes successfully.
However, after I change the variables to int pointers, the return by value of the class does not complete successfully as the integer variables are no longer intact.
I assume the deconstructor is being called when the temporary CVector goes out of scope and deletes these member integer pointers, but the class itself is still returned by value.
I'd like to be able to return by value the CVector with the memory allocated to its member variables intact, whilst ensuring the temporary CVector is correctly deleted when it goes out of scope.
Is there any way this can be done?
Many thanks!
The problem is that you are not following the rule of the three, which basically boils down to: *if you manage resources, then you should provide copy constructor, assignment operator and destructor for your class*.
Assuming that on construction you are allocating memory for the pointers, the problem is that the implicit copy constructor is shallow, and will copy the pointers, but you probably want a deep copy. In the few cases where you do not want a deep copy, control of the manage shared resource becomes more complicated, and I would use a shared_ptr rather than trying to do it manually.
You need to provide a copy constructor for CVector to make copies of the allocated memory. Otherwise, when you return by value, the pointer values will simply be copied and then the temp object is destructed, deallocating the ints. The returned copy now points to invalid memory.
CVector( const CVector& other )
: x ( new int(other.x) )
, y ( new int(other.y) )
{}
Note that it is bad idea to be using raw pointers in your class, especially more than one. If the allocation of y fails above and new throws you've got a memory leak (because x is left dangling). You could've allocated within the constructor itself, instead of the initializer list, either within a try-catch, or using the std::nothrow version of new, then check for nullptr. But it makes the code very verbose and error prone.
The best solution is to use some smart pointer class such as std::unique_ptr to hold pointers. If you were to use std::shared_ptr to hold those pointers, you can even share the ints between copies of the class.
The return-by-value causes the returned, temp object to be copied to another object, a temporary "return object". After temp is copied, it is destructed, deallocating your ints. The easiest way to handle this is to use a reference-counted pointer such as tr1::shared_ptr<>. It will keep the memory allocated until the last reference to it is dropped, then it will deallocate.
There are few problems in the given code.
(1) You should allocate proper memory to *x and *y inside the constructor; otherwise accessing them is undefined behavior.
CVector () : x(new int), y(new int) {}
Also make sure that to have copy constructor and operator = where you delete x and delete y before reallocating them; otherwise it will lead to hazards.
(2) delete them in destructor
~CVector () { delete x; delete y; }
(3) Pass argument to operator + by const reference to avoid unnecessary copying.
CVector CVector::operator+ (const CVector &param)
{
// code
}
Since you are learning with playing around with pointers, I will not comment on the design perspective of your class, like if they should be pointer or variables or containers and so on.