How a 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 output like:

 Say i am in someFunc Null pointer assignment(Run-time error) 

here When an object is passed by the value of SomeFunc, the object's destructor is called when the control returns from the function

Should I be right? if so, why is this happening? and what is the solution for this?

+4
source share
5 answers

Sample is passed by the value of SomeFunc , which means that a copy is made. The copy has the same ptr , so when this copy is destroyed, when SomeFunc returns, ptr is deleted for both objects. Then, when you call PrintVal() in the main, you PrintVal() this invalid pointer. This behavior is undefined. Even if it works, when s1 destroyed, ptr is deleted again, which is also UB.

In addition, if the compiler does not delete the copy in Sample s1= 10; , then s1 will not even be valid for starters, because with temporary destruction, the pointer will be deleted. However, most compilers avoid this copy.

You need to either copy correctly or deny copying. Copy-ctor is incorrect by default for this type. I would recommend either making this type a value type (which contains its members directly, not by pointer), so copy-ctor works by default or uses a smart pointer to store the link so that it can manage the resources for the link for you and copy- ctor will work by default.

One of the things that I really like in C ++ is that it is really friendly with the use of value types around the world, and if you need a reference type, you can simply wrap any value type in a smart pointer. I think this is much better than other languages ​​that have primitive types with semantics, but then user-defined types have reference semantics by default.

+4
source

Usually you need to obey Rule of Three , since you have a pointer.
In your code example, to avoid the Undefined Behavior that you see:

Replace the need for a first application with a mandatory one.

+5
source

Since SomeFunc() takes its argument by value, the Sample object you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.

Since Sample does not have a copy constructor, its creator, created by the compiler, simply copies the pointer value, so both Sample instances point to the same int . When one Sample (temporary copy) is destroyed, this int is deleted, and then when the second Sample (original) is destroyed, it tries to delete the same int again. That is why your program crashes.

You can change SomeFunc() instead of a link, avoiding a temporary copy:

 void someFunc(Sample const &x) 

and / or you can define a copy constructor for Sample that selects a new int , rather than just copying a pointer to an existing one.

+1
source

When you pass an argument to a function that he called a copy constructor, but you don’t have one, the pointer is therefore not initialized. When it exits the function, the object calls the destructor to remove the unified pointer, so it makes an error.

0
source

Instead

 int main() { Sample s1= 10; SomeFunc(s1); s1.PrintVal(); } 

try using

 int main() { Sample* s1= new Sample(10); SomeFunc(*s1); s1->PrintVal(); } 
0
source

Source: https://habr.com/ru/post/1392510/


All Articles