how the destructor works in c++ - 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();
}

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.

return *this; deletes pointers

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.

Copy Constructor : When storage is freed?

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.

how to call a function when auto_ptr is a parameter of it!

#include <iostream>
#include <memory>
class test
{
private:
int x , y;
public:
test(int a , int b):x(a),y(b){}
void fun()
{
std::cout<< x<<" "<<y<<" "<<std::endl;
}
};
void show(std::auto_ptr<test> t1)
{
t1->fun();
}
int main()
{
show(new test(3,4));
}
I am getting a compilation error , please tell me what's wrong in this code?Thanks in advance.
Whenever you dynamically allocate an object, you should create a named smart pointer that immediately takes ownership of the object, then use that named smart pointer. For example,
std::auto_ptr<test> ptr(new test(3, 4));
show(ptr);
You cannot pass new test(3, 4) directly to the function because std::auto_ptr objects must be explicitly constructed; it would be quite unexpected if a smart pointer took ownership of an object implicitly.
That said, this is rather unusual anyway because when you call show(), the auto_ptr is copied and when auto_ptr is "copied," the original loses ownership and the copy gains ownership (so, after show() is called, you will find that ptr no longer has ownership of the object.
James explained how to resolve the problem.
But the reason auto_ptr was designed so that you can not do this:
show(new test(3,4));
Is because this is a bad idea.
Even this (if it were allowed):
show(std::auto_ptr<test>(new test(3,4)));
Would be a bad idea.
So you ask why.
Well in the normal situation not a big deal.
Bu what happens when you have a function that takes more than one parameter.
show2(std::auto_ptr<test>(new test(3,4)), SomeObject());
Now the standard gurantees that all parameters will be fully evaluated before the call (even the construction of the auto_ptr). But it does not guarantee the evaluation order nor that the evaluation will not be interleaved.
Thus it is possible for this evaluation:
// Phsedu code for parameter evaluation
test* tmp1 = new test(3,4);
SomeObject const& tmp2 = SomeObject();
std::auto_ptr<test> const& tmp3(tmp1);
call(tmp3, tmp1)
This order is bad. Because if the constructor of SomeObject throws an exception you will leak tmp1 as it has not yet been assigned to the std::auto_ptr.
This is why we auto_ptr was designed so that you have to give it a named variable.
std::auto_ptr<test> tmp3(new test(3,4));
SomeObject tmp1;
call(tmp3, tmp1)
Now if SomObject constructor throws the test object will be tidied up.

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.