Reputation: 3131
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
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
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
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
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
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