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()没有意义。