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
Sampleobject is allocated on the heap and thenewexpression returns a pointer to it, aSample*. - You cannot assign a
Sample*to a variable of typeSample. ButSamplehas a constructor that allows implicit construction from an int. If you use the-fpermissivecompiler 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
s1is constructed by interpreting the memory address of the heapSampleobject as an integer (truncating it ifsizeof(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:
s1is copied to callSomeFunc(). The copy is available asxin the function. Because of the default pointer copy boths1andxpoint to the sameintobject.xgoes out of scope at the end of the function, the destructor runs and deletes theintobject.
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.
solved Getting undefined behavior for something that shouldn’t be getting undefined behavior