Conditional statement limitations ::

I use GCC 4.5 and observe very peculiar behavior. I am wondering if there is anything with this operator that I do not quite understand. I thought I own C ++. I have a thin C ++ Wnd for Windows HWND objects with implemented operator cast operator HWND ...

If I use a conditional statement like this (given input Wnd *p and example function SetParent(HWND)) :

 SetParent((p!=NULL) ? (HWND)(*p) : NULL) 

The parent is correctly set to NULL or p depending. This is what I would expect. However, if you dare to be lazy and write:

 SetParent(p ? *p : NULL) 

everything has gone. After starting GDB, I found that the destructor is called in the variable p after calling SetParent . Any ideas what is going on here?

Edit Here is my Wnd class:

 class Wnd{ HWND m_hwnd; ///< the actual handle WndFake *fake; ///< store state here if we do not have a handle public: virtual ~Wnd(); //contructor s Wnd(HWND wnd=NULL):m_hwnd(wnd),fake(NULL){} Wnd(DWORD sty,const jchar *title,const RECT &sz); operator HWND(){return m_hwnd;} operator HWND() const {return m_hwnd;} } 
+6
source share
3 answers

I suspect your Wnd also has an implicit conversion constructor that accepts HWND or even int? If so, make it explicit.

Does your Wnd probably have no copy constructor and = operator declared? declare these private and do not define them.

Also remove the operator HWND and add the HWND hwnd() const; member function HWND hwnd() const; to your wnd. Then the code will look readable, for example:

 Setparent( p ? p->hwnd() : NULL ); 

I believe that when these mods are completed, you will find out what is wrong with your Wnd.

The problem appears because the operands on both sides: in ?: must be of the same type, so NULL (0) is somehow converted to Wnd. So, a temporary copy of * p is made as the return value ?: Then the HWND statement is called.

+4
source

Is the destructor called by the variable p or some temporary variable that is a copy of p?

In the first example, you use c-style cast to convert *p to HWND . In the second case, you allow the compiler to perform the conversion, and this may require a copy of *p .

+3
source

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() .

+2
source

Source: https://habr.com/ru/post/889411/


All Articles