The operands of the ?: Operator must be cast to the common type that will be used as a result. When you use
SetParent(p != NULL ? (HWND) *p : NULL);
you essentially manually force the situation when the compiler chooses the general type of HWND . That is, the above option is equivalent
SetParent(p != NULL ? (HWND) *p : (HWND) NULL);
But when you do
SetParent(p != NULL ? *p : NULL);
language rules work differently, the compiler will determine the general type differently. This is not the general type of HWND , but your Wnd . Both operands are converted to Wnd , and the latter is interpreted as
SetParent(p != NULL ? *p : Wnd(NULL));
those. when p is null, the compiler creates a temporary Wnd(NULL) object (using the transform constructor you provided) and returns it as the result. Moreover, the compiler will most likely also build a temporary object in the true branch (using the copy constructor). Then, the resulting temporary object is converted to the HWND type (since this requires SetParent ), so all this is interpreted as
SetParent((HWND) (p != NULL ? Wnd(*p) : Wnd(NULL)));
Then, the temporary object is destroyed immediately after calling SetParent . This is the destruction that you observed, except that you misinterpreted it as the destruction of p .
The reason the compiler can choose this approach is because the conversion constructor is not explicit declared. If you declare an explicit conversion constructor
class Wnd { ... explicit Wnd(HWND wnd=NULL) : m_hwnd(wnd), fake(NULL) {} ... };
the compiler can no longer use to implicitly convert NULL to Wnd . In this case, the compiler will be left without a choice, but the usual type will be used instead of HWND
SetParent(p != NULL ? (HWND) *p : (HWND) NULL);
just as you wanted it.
PS When you already have operator HWND() const in your class, it makes no sense to implement an identical version of non-const operator HWND() .