Can anyone explain the meaning of *p=*q in this C++ code? Is this a copy constructor concept?
class A{
//any code
}
int main(){
A *p=new A();
A *q=new A();
*p=*q;
return 0;
}
Is this a copy constructor concept?
No, what you are referring to is a copy assignment concept. Consider this:
int* p = new int{9};
int* q = new int{10};
*p = *q;
As you can see above, only the value of the variable q which is pointed to is copied. This is the equivalent of the copy assignment for objects. If you were to do this:
p = q;
Then this would not be a copy assignment, because both int's point to the same address and value, meaning any change to p or q would be reflected on the other variable.
To give a more concrete and validated example, here is some code:
int main()
{
int* p = new int{9};
int* q = new int{10};
*p = *q;
//p = 10, q = 10
*p = 11;
//p = 11, q = 10
delete p;
delete q;
}
And here is a supplementary counter-example
int main()
{
int* p = new int{9};
int* q = new int{10};
p = q;
//p = 10, q = 10
*p = 11;
//p = 11, q = 11
delete p;
//delete q; Not needed because p and q point to same int
}
As you can see, the changes are reflected on both variables for p=q
Side Note
You mentioned copy-construction, but you were unclear about the concept. Here is what copy-construction would have looked like:
int* p = new int{9};
int* q = new int{*p}; //q=9
Copy construction differs from copy assignment in the sense that with copy construction, the variable doesn't already have a value, and for an object, the constructor has yet to be called. Mixing up the 2 terms is common, but the fundamental differences make the two concepts, well, different.
It looks like, you're unclear about the copy constructor and copy assignment. Let's first have a look at both concepts individually, and then I'll come to your question. The answer is a little long, so be patient :)
Copy Constructor
Here, I'm not going to explain how to write a copy constructor, but when the copy constructor is called and when it's not. (If you want to know, how to write a copy constructor, see this)
A copy constructor is a special constructor for creating a new object as a copy of an existing object. (It is called whenever there's a need for making a copy of an existing object)
These are the scenarios when the copy constructor will be called to make the copy of an existing object:
Initializing an object with some previously created object:
SomeClass obj;
// ...
SomeClass anotherObj = obj; // here copy constructor will be called.
See, SomeClass obj; statement is simply creating an object (here, default constructor will be called to create the object). The second statement SomeClass anotherObj = obj; is instantiating an object, initialized with the values of obj (an existing object), so copy constructor will be called here. You can also initialize an object with an existing object this way: SomeClass anotherObj(obj); (This statement is equivalent to SomeClass anotherObj = obj;)
Except:
If you initialize with some rvalue expression. e.g.
SomeClass someObject = aObject + anotherObject;
In this case, move constructor will be called. See, What are move semantics?
Passing an object by value to some function (see Passing arguments by value):
See, the following code snippet, here the function doSomething is accepting an object as parameter by value:
void doSomething(SomeClass someObject)
{
// ...
}
There are some cases, when there will be a need to make the copy of the passed argument in the parameter object someObject, I've listed when there will be a need to make the copy and when there'll not be a need.
Have a look at the following code snippet:
SomeClass someObject;
// ...
doSomething(someObject); // here copy constructor will be called.
The statement SomeClass someObject; is just instantiating someObject by calling the default constructor.
The second statement doSomething(someObject); is calling the function doSomething previously shown, by passing someObject as argument. This is the case, when there's a need to make a copy of someObject to pass to the function.
Except:
Similiary, If we call doSomething with some rvalue expression, it will call move constructor instead of copy constructor.
Returning an object from a function by value:
Let's have a look at the following definition of doSomething
SomeClass doSomehing()
{
SomeClass someObject;
// ...
return someObject;
}
In the above function doSomething, an object of SomeClass is being created and after doing some task, the object is being returned by the function, in this case, a copy of the someObject will be created and returned.
Except:
Similiary, If doSomething returns some rvalue expression, it will call move constructor instead of copy constructor.
Copy Assignment
Copy Assignment is usually confused with the copy construction, let's have a look at how it is different than the copy construction:
SomeClass someObject;
// ...
SomeClass anotherObject;
// ...
anotherObject = someObject; // here copy assignment operator will be called.
The first two statements are just creating someObject and anotherObject, you see, the third statement is actually calling the copy assignment operator and not the copy constructor.
Constructors are only called when some new object is being created. And in the case of anotherObject = someObject;, both the objects are already created, so there won't be any call to the copy constructor. Instead a copy assignment operator will be called (to see, how to overload a copy assignment operator, see this)
Now, let's have a look at your code snippet:
A *p=new A();
A *q=new A();
*p=*q;
In the first statement A *p=new A();, default constructor will be called to create an object (in this case, new object will be created on heap) and p will be initialized with the address of the newly created object (as p is a pointer)
Similar is the case with second statement A *q=new A(); (It is creating another object and q will be initialized with newly created object)
Now, the third statement: *p = *q; (here * is Dereference operator)
To understand, what the third statement is doing, let's have a look at some pointers and de-referencing them to get the actual object, which they're pointing to.
int someVariable = 5;
int *somePointer = &someVariable;
// ...
*somePointer = 7;
Let's try to understand the above code snippet: someVariable is created and initialized with a value of 5, then somePointer is created and initialized with the address of someVariable.
Now, the last statement *somePointer = 7;, it is actually de-referencing the somePointer and by de-referencing, it'll get the the variable which it is pointing to. (so it will get someVariable) and then it is assigning 7 to it. So after this statement, someVariable's value will become 7
Let's have another example:
int* somePointer = new int;
int* anotherPointer = new int;
// ...
*somePointer = 5;
*anotherPointer = 7;
// ...
*somePointer = *anotherPointer;
First, somePointer will be created and initialized with the address of dynamically allocated int variable (will be allocated in heap, see Dynamic Allocation in c++), similarly, anotherPointer will be initialized with the address of another dynamically allocated variable.
Then, it is assigning 5 to the first variable (which is being pointed by somePointer) and 7 to the second variable (which is being pointed by anotherPointer)
Now, the last statement will be of your interest, *somePointer = *anotherPointer;, in this statement *somePointer is de-referencing and getting the first variable (whose value was 5) and *anotherPointer is de-referencing and getting the second variable (whose value is 7), and it is assigning the second variable to the first variable, resulting in changing the first variable's value to 7.
Now, let's have a look at your *p=*q; statement, (p was pointing to the first object of A, and q was pointing to the second object of A, both dynamically allocated), *p will dereference p and get the first object, *q will dereference q and get the second object, and then the second object will be copied in the first object, and if you see, no new object is being created in *p=*q;, and only the value of second object is being created in the first object, so copy assignment operator will be called here and no the copy constructor.
Another thing
You should de-allocate the dynamically allocated memory which you borrowed using new operator:
delete p;
delete q;
You should add these two lines at the end of your program, so to avoid Memory Leak.
As stated in the comments, one need to understand the basics first:
With A *p=new A(); one gets a pointer to a memory region on the heap in which an object of type A is constructed.
With *p one dereferences the pointer, i.e. one retrieves the object.
Now *p = *q uses the (possibly implicitly declared) assignment operator of class A in order to give *p -- the object pointed to by p -- the value of *q. This operation could equivalently be written as p->operator=(*q).
The last step, the assignment, is identical to what you would obtain with objects instead of pointers (which is usually a better way to go in C++ and often called RAII):
A r;
A s;
r=s;
Related
I'm attempting to call my copy constructor in my assignment operator overload. I assign the result of the copy constructor to a pointer called temp, then set the this pointer to equal temp. This results gives me the error: lvalue required as left operand of assignment. I thought this was a pointer to my object. Why is there an issue with reassigning the pointer to a different object?
In the passing case I defereence this(*this) and set it equal to temp. To me this means I'm saying the actual object is equal to a pointer. Am I misinterpreting the meaning of this?
Passing case:
Foo *temp = new Foo(other); //invokes copy constructor
*this = temp;
Failing case:
Foo *temp = new Foo(other); //invokes copy constructor
this = temp;
Full source code:
TreeNode::TreeNode(TreeNode *other) {
this->leftChild = other->leftChild;
this->rightChild = other->rightChild;
this->data = other->data;
}
TreeNode& TreeNode::operator=(TreeNode *other) {
if(this != other) {
TreeNode *temp = new TreeNode(other);
this = temp;
}
return *this;
}
1) this is a built-in rvalue expression that every class has (meaning it cannot be modified as per C++ standard), and it always points to the instance of the class (the object) making the function call.
2) *this is always an lvalue, i.e. it must have an address in memory, i.e. it represents an object that can be modified.
So when you dereference this:
*this = temp
You have an lvalue, affiliated with a space in memory, but not with
this = temp
For a detailed discussion of rvalues and this:
What is "rvalue reference for *this"?
Type of 'this' pointer
As is, this code seems a bit problematic. Consider what happens when you do something like:
treenode1 = treenode2; //assuming both are pointers to TreeNode objects
The compiler sees the lvalue treenode1 (to whose object 'this' will always refer during the operation), then sees the '=', notes the overload, then uses pointer treenode2 to create a NEW copy of the object treenode2 is pointing to (binding the lvalue temp to the new object), then tries to copy the values in temp over into the original treenode1-bound object (we have three TreeNodes now existing, I believe).
What you don't want is to have that temp object hanging around after this convoluted operation is done, I believe, as that would cause a memory leak. So you'd need to delete it before. So if you absolutely had to do this for some reason, the solution is a move assignment operator, which is designed for use with temporary objects. Probably best to avoid this pattern altogether however, it seems very liable to give memory leaks.
I have a Double free or corruption (fasttop) error on this code.
I think i missed something on the "copy constructor".
class Vector{
int taille;
int* ptr;
public:
Vector():taille(0), ptr(NULL){
...
}
Vector(int n){
...
}
//The most important one
Vector(const Vector& source){
if(source.ptr != NULL){
taille = source.taille;
ptr = new int[taille];
for(int i=0;i<taille;i++) ptr[i]=source.ptr[i];
}else{
taille=0;
ptr=NULL;
}
cout << "Copy constructor" << endl;
}
~Vector(){
if(ptr!=NULL) delete ptr;
}
};
And here's the test :
int main()
{
Vector b(5);
Vector a(b);
a=Vector(12);
return 0;
}
The above = operator does not call the copy constructor. Why ?
It says : "double free or corruption (fasttop)"
With the expression
a = Vector(12)
a few things are happening:
First a new temporary Vector object is created (from Vector(12)). This is constructed using the Vector(int) constructor.
The temporary object is assigned to a, using a.operator=(<temporary object>).
The default compiler-generated operator= function does a simple member-wise assignment, i.e. it basically does ptr = other.ptr. This means you now have two objects ptr members pointing to the same memory: The temporary object, and a.
The temporary object is destructed once the assignment is made. This means the memory occupied by that object is passed to delete (which really should be delete[]).
This of course means that a.ptr is no longer pointing to valid memory, and when it later goes out of scope and is destructed you try to delete the already deleted memory.
There is no copy-construction going on here. It's all copy-assignment. Copy construction is only used on actual construction, when an object is created (temporary or not). I think you're confused because the = symbol can be used for copy-construction, as in
Vector a = b; // This is a copy-construction
// The copy-constructor of `a` is called with
// a reference to `b` as argument
// It's equal to `Vector a(b)`
This is very different from assignment
a = b; // This is a plain assignment
// It is equal to `a.operator=(b)`
The crash is solved by following one of the rules of three, five or zero.
I also recommend you read e.g. this canonical assignment operator reference.
You are creating a temporary Vector in the assignment a = Vector(12), which is being assigned via operator= to a. The temporary Vector gets destroyed at the end of the assignment statement, and a gets destroyed at the end of the function. Both point at the same allocated array because you did not define a copy-assignment operator=:
http://www.cplusplus.com/doc/tutorial/operators/
What i think is occuring is that the rvalue A returned by SetVar is an identical copy to Class and shares the same pointer Var. but when the rvalue calls its deconstructor it deletes Class's Val.
class A
{
private:
int* Var;
public:
A SetVar(int);
~A()
{
delete Var;
}
};
A A::SetVar(int NewVar)
{
Var=new int;
*Var=NewVar;
//POINT A
return *this;
}
int main()
{
A Class;
Class.SetVar(8);
//POINT B
}
At POINT A *Val equals 8, but at POINT B *Val equals -17891602. I also Get _BLOCK_TYPE_IS_VALID(pHead->nHeadUse) due to trying to delete Val twice.
deleting the deconstructor solves the issue but creates a memory leak.
You have violated The Rule of Three
So, you make a copy of the object when you do
return *this
which gets destructed as well, and delete is called twice on the same pointer. You really shouldn't be doing this anyway. You should return a reference, but why should a setter function return a reference to the object it was called on anyway? Isd it to chain function calls?
Additionally, you are leaking Var every time you reassign it.
There are a few problems here.
First, the most direct cause of you problem is that a copy of the this object is made when SetVar() returns. (You probably want to return a reference to an A instead.) Since there is no copy constructor defined for class A, the values of all of the fields are implicitly copied. This means that the copy will have a pointer to the same Var int that you allocated in SetVar. In other words, you will have two pointers to the same memory, one in the original A variable (the one you call "Class") and one in the copy that is returned by SetVar(). When the second of these is destroyed, its destructor will be deleting the memory at an already-deleted pointer.
I have code:
T x,y;
T* t = new T[10];
t[0] = x;
t[0] = y;
What happens:
new T[10] makes array invoking default constructor.
t[0] is dereferenced pointer?
So if I assign value x, x is copied (T copy constructor is invoked);
next if i assign y value to same position next copy constructor is invoked or assignment operator? Is old value properly destroyed?
In your example:
T* t = new T[10];
invokes the default constructor of T (10 times). Then
t[0] = x;
invokes the assignment operator. This statement invokes no constructor.
T* t = new T[10];
Creates 10 objects of the type T on the freestore(Heap) by calling default constructor of T.
Note that when you use new objects are always created on Freestore.
When you assign,
t[0] = x;
The copy assignment operator(=) a.k.a assignment is invoked.Neither the constructor nor the copy constructor is invoked here.
For simplicity remember the following rules:
When a object is being created and assigned to in same statement, then copy constructor will be used. This is known as Copy Initialization.
Example:
Myclass obj1;
Myclass obj2 = obj1; //obj2 is Created & Initialized in same statement
When a object is already created in a previous statement and being assigned(=) to in another statement then the assignment operator will be called.
Example:
Myclass obj1; //obj1 is created
Myclass obj2; //obj2 is created
obj2 = obj1; //Already created object obj2 is assigned with obj1
Your examples fall in the second scenario.
here is my c++ code :
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
it returns me the output like :
Say i am in someFunc
Null pointer assignment(Run-time error)
here As the object is passed by value to SomeFunc the destructor of the object is called when the control returns from the function
should i right ? if yes then why it is happening ? and whats the solution for this ???
Sample is passed by value to SomeFunc, which means a copy is made. The copy has the same ptr, so when that copy is destroyed when SomeFunc returns, ptr is deleted for both objects. Then when you call PrintVal() in main you dereference this invalid pointer. This is undefined behavior. Even if that works then when s1 is destroyed ptr is deleted again, which is also UB.
Also, if the compiler fails to elide the copy in Sample s1= 10; then s1 won't even be valid to begin with, because when the temporary is destroyed the pointer will be deleted. Most compilers do avoid this copy though.
You need to either implement copying correctly or disallow copying. The default copy-ctor is not correct for this type. I would recommend either making this type a value type (which holds its members directly rather than by pointer) so that the default copy-ctor works, or use a smart pointer to hold the reference so that it can manage the by-reference resources for you and the default copy-ctor will still work.
One of the things I really like about C++ is that it's really friendly toward using value types everywhere, and if you need a reference type you can just wrap any value type up in a smart pointer. I think this is much nicer than other languages that have primitive types with value semantics but then user defined types have reference semantics by default.
You usually need to obey the Rule of Three since you have an pointer member.
In your code example to avoid the Undefined Behavior you are seeing:
Replace the need to in first statement by must.
Since SomeFunc() takes its argument by value, the Sample object that you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.
Since Sample has no copy constructor defined, its compiler-generated copy constructor simply copies the pointer value, so both Sample instances point to the same int. When one Sample (the temporary copy) is destroyed, that int is deleted, and then when the second Sample (the original) is destroyed, it tries to delete the same int again. That's why your program crashes.
You can change SomeFunc() to take a reference instead, avoiding the temporary copy:
void someFunc(Sample const &x)
and/or you can define a copy constructor for Sample which allocates a new int rather than just copying the pointer to the existing one.
When you pass the argument for the function it's called the copy constructor, but you don't have one so the pointer is not initialised. When it exits the function, the object is calls the destructor to delete the unitialised pointer, so it thows an error.
Instead of
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
try to use
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}