Copy Constructor : When storage is freed? - c++

Given the 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();
}
The output is :
Say i am in someFunc
Null pointer assignment(Run-time error)
I'm not able to understand why the second line of output comes. The second line of the output. I think that the compiler supplies a copy constructor when it is not explicitly specified. So, in the function SomeFunc(Sample x), the local object to SomeFunc() which is X of Sample type should be created and destroyed and the Sample type object (s1) in main() should remain intact and should be freed only after main exits. Please answer why the above behaviour is happening?

Why the above behaviour is happening??
Short Answer:
Because You are not following the Rule of Three.
Long Answer:
Your class has a pointer member ptr with dynamic memory allocation in constructor and deallocation in destructor while your code creates temporary copies of the object while passing to the function SomeFunc() by calling copy constructor, implicitly generated by the compiler, which creates a shallow copy of the pointer member. Once the temporary is destroyed at the end of function call the memory is deallocated in destructor and you are left with a dangling pointer.This invalid pointer is dereferenced further when you call the function PrintVal() resulting in a Undefined Behavior, which manifests in the form of a segmentation fault.
How to avoid this problem?
Short Answer:
Follow the Rule of Three.
Long Answer:
You should provide a copy constructor which creates a deep copy of the pointer member ptr. This ensures that the pointer member of the object created in member remains valid through out the lifetime of the program.
EDIT:
Actually, the problem might even occur even before the function gets called, specifically when you call:
Sample s1= 10;
This calls the conversion constructor,
Sample(int i)
to create a temporary Sample object which is then used for constructing s1 object by calling the implicit copy constructor, If this is the case the temporary object created will be destroyed after creation of s1 does leaving the pointer member ptr in a dangling state.
However, most of the compilers will apply optimizations through copy elision using Return Value Optimization(RVO) thus eliminating the need of calling the copy constructor & hence this might not be a problem.
In either case solution to the problem remains the same.

Related

the location of delete in the class to delete pointer data member

I write a simple class, I just wanna know where I should delete my pointer.
#include<iostream>
class test
{
private:
int* sum{new int};
public:
int addFunc(int num1 = 5, int num2 = 2)
{
*sum = num1 + num2;
return *sum;
}
void print()
{
std::cout << *sum << std::endl;
}
};
int main()
{
test obj;
obj.addFunc();
obj.print();
}
I know how to use unique pointers to get rid of deleting pointers, should I delete my pointer after
returning it or somewhere else.
You delete it in the destructor. But if you're managing raw memory you'll also have to implement a suitable copy constructor & copy assignment operator and their move counterparts.
In 99%+ of these cases you'll just want to use automatic lifetime or smart pointers instead.
Short answer: never, meaning at program end.
The problem is that your class is copyable. If you delete the pointer in destructor (which would be the correct place for something allocated at construction time), you will get a dangling pointer in the following use case:
you pass a reference to a test object to a function
inside that function you copy the object to a local object: the pointer will be copied so both the original object and the local copy will point the the same int
at the end the the function, the local object will be destroyed. If if deletes the int, the original will get a dangling pointer.
Long story made short: as soon as you use allocation at construction time, you should care for the copy/move construction and assignment, and destruction.

Copy constructor return temporary object

I was preparing lecture on copy constructor and found this:
MyClass myFunction()
{
MyClass mc;
return mc;
}
the statement says:
If we call myFunction, then C++ will create a new myClass object
that's initialized to mc when myFunction returns. Thus while your code
might act like it's transparently moving the object from inside of
myFunction to the rest of your code, it's actually making a temporary
copy.
I think statement MyClass mc; will create the object and it returned form function not any temporary object.
Where am I going wrong? Can somebody elaborate the statement to be able to understand easily?
I think statement MyClass mc; will create the object
Correct.
and it returned form function not any temporary object.
I don't fully understand your statement, so I cannot tell whether you've gone wrong, but this is what happens:
mc is a local variable. Local variables are destroyed when the function exits. Before it is destroyed, a temporary object is copy-initialized from it. The temporary object is then returned from the function.
Extra knowledge 1: Since C++11, the temporary is copy-initialized by move, if possible.
Extra knowledge 2: Standard explicitly allows the compiler to skip the copy/move and instead construct the object at the call site. This optimization is known as (named) return value optimization and is a form of copy elision. Despite this, you can not return objects that are neither copyable nor movable. That is because an implementation of C++ is not required to do NRVO.
Let's say you have this code:
#include <iostream>
using namespace std;
class MyClass
{
public:
int *v;
MyClass()
{
v=new int[5];
for(int i=0;i<5;i++) v[i]=i; // x will look like : 0,1,2,3,4
}
~MyClass()
{
cout<<"Destructor called! Now v is deallocated! \n";
delete[] v;
}
};
MyClass myFunction()
{
MyClass mc;
return mc;
}
int main()
{
MyClass x;
x=myFunction();
cout<<x.v[2]<<'\n'; //it may or may not print the right thing
return 0;
}
As you can see, myFunction returns the object mc like you said. But you also know that the destructor of mc will be called when mc goes out of scope - mc is declared inside myFunction, so the destructor will be called after the function is executed and memory will be freed (delete[] v). The memory is deallocated, but the values are still there in the memory! So, even though x=myFunction(); will work, you will have an object where the memory v points to is deallocated! So, cout<<x.v[2]<<'\n'; may not print the right thing. If you compile the code it will probably print the correct value (2), because the memory was not overwritten, but if you would do some more allocations before the cout statement, or after some time of using your OS, you will see that the value printed is incorrect/crash as the memory will be overwritten by other programs. v still points to that memory block, but it doesn't know what's there because the memory is deallocated.
Inside myFunction: v -> |0|1| 2 |3|4|...
After exiting myFunction: v -> |0|1| 2 |3|4|.....
After some memory allocations: v -> |a|1| b |#|%|3|7|2|1|*|!|......

Explaining copy constructor example

A copy constructor is used for many things such as when I need to use pointers or dynamically allocate memory for an object. But looking at this example at tutorialpoint.com:
#include <iostream>
using namespace std;
class Line
{
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main( )
{
Line line(10);
display(line);
return 0;
}
the result is :
Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!
and when I commented out (the copy constructor) and the code inside destructor I got the same results:
Normal constructor allocating ptr
Length of line : 10
So what is the difference between using the copy constructor here or not? Also why does "Freeing Memory!" occur twice?
The argument to the display() function is passed by value, so the compiler calls the copy constructor to create it. When the class defines its copy constructor you get the correct semantics: the copy constructor makes a copy, and that copy has its own memory to hold the length. When you remove the copy constructor, the compiler generates one for you, and the copy that gets passed to display() has the same pointer as the original. When that copy gets destroyed it deletes the memory that ptr points to. When the original gets destroyed it deletes the same memory again (which happens to have no visible effects here). That's definitely not what you want to have happen, which is why you need to define a copy constructor. As #Joe says: inside the destructor, print the value of `ptr' to see this more clearly.
Print the address of the memory being freed.
I believe you will find the compiler generated the constructor for you, did a value copy of the contents, including the pointer, and you are double-freeing the pointer and just getting lucky that the runtime isn't complaining about it.
The compiler generated copy constructor is still being called - nothing has changed in that regard, you just aren't printing anything from it since you didn't write it.
If we don’t define our own copy constructor, the C++ compiler creates a default copy constructor for each class which does a member wise copy between objects. The compiler created copy constructor works fine in general. We need to define our own copy constructor only if an object has pointers or any run time allocation of resource like file handle, a network connection..
A constructor of some type T of the form
T (const & T);
The single argument must be a const reference to an existing object of same type
Creates a duplicate of the existing object
Used whenever a copy of an object is needed
Including arguments to functions, results returned from functions
Problems with pointer-based arrays in C++:–
No range checking.
Cannot be compared meaningfully with ==
No array assignment (array names are const pointers).
If array passed to a function, size must be passed as a separate argument.

how the destructor works in c++

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();
}

Getting undefined behavior for something that shouldn't be getting undefined behavior

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 = new Sample(10);
SomeFunc(s1);
s1.PrintVal();
}
Two things that I think should happen:
s1 can be initialized using the parameterised constructor.
The value of *ptr from PrintVal() should be 10.
For 1) I'm getting invalid conversion from 'Sample*' to 'int' [-fpermissive]. I'm calling the constructor properly, why is this happening?
For the case of 2) I'm getting either a garbage value or the program gets an segmentation fault. This shouldn't happen because the ptr of the local object x of the SomeFunc should be deleted not the ptr of s1 as it is passed by value not reference. IIRC pass by value for objects sends a copy of the object to the function's receiving arguments.
Your code does have undefined behaviour. But let’s start at the beginning.
Sample s1 = new Sample(10);
This is what happens in this line:
A Sample object is allocated on the heap and the new expression returns a pointer to it, a Sample*.
You cannot assign a Sample* to a variable of type Sample. But Sample has a constructor that allows implicit construction from an int. If you use the -fpermissive compiler option (hint: don’t!), the compiler allows implicit conversion of a pointer to an integer – after all, a pointer is just a memory address, a.k.a. a number.
Accordingly s1 is constructed by interpreting the memory address of the heap Sample object as an integer (truncating it if sizeof(Sample*) > sizeof(int)). That’s the value that ends up as *(s1.ptr).
To reiterate the key point: In that line you don’t instantiate one Sample object, but two. Bug 1: The one created on the heap is never deleted. That’s a memory leak.
SomeFunc(s1);
Sample has nothing in it that prevents the compiler from generating the default copy constructor and default copy assignment operator. Important: “default” for pointers means to copy the pointer, not the object behind it. So:
s1 is copied to call SomeFunc(). The copy is available as x in the function. Because of the default pointer copy both s1 and x point to the same int object.
x goes out of scope at the end of the function, the destructor runs and deletes the int object.
We are not quite undefined yet, but we’re getting close.
s1.PrintVal();
The function tries to acces the int object behind the pointer, but it’s already deleted. s1.ptr is a dangling pointer. Bug 2: Dereferencing a dangling pointer is undefined behaviour.
And all that because of that seemingly innocent implicit pointer-to-int conversion … That’s why it is a compiler error by default, at least in non-ancient compilers.