Milan Mendpara
Milan Mendpara

Reputation: 3131

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 ???

Upvotes: 5

Views: 4065

Answers (5)

bames53
bames53

Reputation: 88215

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.

Upvotes: 5

kochobay
kochobay

Reputation: 392

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

Upvotes: 0

Wyzard
Wyzard

Reputation: 34571

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.

Upvotes: 1

Andrei
Andrei

Reputation: 100

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.

Upvotes: 0

Alok Save
Alok Save

Reputation: 206616

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.

Upvotes: 5

Related Questions