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 call- SomeFunc(). The copy is available as- xin the function. Because of the default pointer copy both- s1and- xpoint to the same- intobject.
- xgoes out of scope at the end of the function, the destructor runs and deletes the- intobject.
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