6

我正在使用GCC 4.5並觀察到非常奇怪的行爲。我想知道這個操作符是否有一些我不完全理解的東西。我認爲我精通C++。 我有一個瘦C++包裝類Wnd對於Windows HWND對象與實施投型運算符operator HWND ...有條件運算符的侷限性?:

如果我使用條件運算符是這樣的(給定輸入Wnd *p和樣本功能SetParent(HWND)):。

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

父已正確設置爲NULLp取決於這就是我所期待 但是,如果敢偷懶,寫:

SetParent(p ? *p : NULL) 

東西就會失控 運行GDB後,我發現,調用析構函數在瓦里在致電SetParent後能夠致電p。 有什麼想法發生在這裏?

編輯 這裏是我的Wnd中類:

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;} 
    } 
+9

你很可能會需要出示完整的'Wnd'類定義。 – 2011-05-31 00:14:07

+0

@bacchus,注意你的'(HWND))'編輯錯了:d雖然改進間距不錯... – sarnold 2011-05-31 00:17:18

+0

@sarnold額外的支架是從句子。我錯過了。感謝您的警告;) – bacchus 2011-05-31 00:20:57

回答

4

我懷疑你有Wnd的非顯式轉換構造太那個需要HWND甚至詮釋? 如果是這樣,那麼明確。

你的Wnd可能沒有複製構造函數和operator =聲明?聲明這些是私人的,不要定義它們。

同時刪除operator HWND並添加成員函數HWND hwnd() const;您Wnd中。然後代碼將看起來像可讀:

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

我相信,當這些MODS完成後,你會發現你的Wnd有什麼問題。

的問題表現在,因爲兩邊的操作數:在:必須是同一類型,以便NULL(0)是某種轉換爲Wnd中。所以* p的臨時副本被作爲?的返回值:然後運算符HWND被調用。

+0

+1我認爲,去除隱式轉換從'HWND'到'Wnd'應該做的伎倆,因爲這會禁止'NULL'到'Wnd',編譯器將被迫向相反的方向轉化的轉化。無論如何,刪除隱式轉換將使代碼更具可讀性和可維護性是完全正確的。 – 2011-05-31 07:44:12

3

上稱爲變量p或一些臨時變量是p的副本析構函數?

在您的第一個示例中,您正在使用c-style轉換將*p轉換爲HWND。第二,您讓編譯器進行轉換,並且可能涉及製作*p的副本。

2

?:操作的操作數必須被帶到常見的類型,其將在結果被使用。當您使用

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

你基本上是手動強制的情況下,當編譯器有選擇常見的類型是HWND。即上述變異相當於

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

但是當你做

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

的語言文字工作的規則不同,編譯器將不同決定常見的類型。在此常見類型不是HWND,而是您的Wnd。兩個操作數都轉換爲Wnd,後一個變體解釋爲

SetParent(p != NULL ? *p : Wnd(NULL)); 

即,當p爲空時,編譯器會構造一個臨時對象Wnd(NULL)(使用您提供的轉換構造函數)並將其作爲結果返回。而且,編譯器很可能也會在真正的分支中構造一個臨時對象(通過使用複製構造函數)。然後將得到臨時的對象將轉換爲HWND類型(因爲這是SetParent要求),所以整個事情被解釋爲

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

臨時對象,然後調用SetParent後立即銷燬。這是你觀察到的破壞,除非你錯誤地將其解釋爲破壞p

編譯器可以選擇這種方式的原因是因爲您的轉換構造函數未聲明explicit。如果你聲明的轉換構造explicit

class Wnd { 
    ... 
    explicit Wnd(HWND wnd=NULL) : m_hwnd(wnd), fake(NULL) {} 
    ... 
}; 

編譯器將不再能夠使用隱式轉換NULLWnd。在這種情況下,編譯器將別無選擇地離開,但使用HWND作爲一種常見的,而不是

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

就像你想它。

P.S.如果您的班級中已有operator HWND() const,則實施相同的非常量版本operator HWND()沒有意義。