有条件运算符的局限性?:
我正在使用GCC 4.5并观察到非常奇怪的行为。我想知道这个操作符是否有一些我不完全理解的东西。我认为我精通C++。 我有一个瘦C++包装类Wnd
对于Windows HWND
对象与实施投型运算符operator HWND ...
。有条件运算符的局限性?:
如果我使用条件运算符是这样的(给定输入Wnd *p
和样本功能SetParent(HWND))
:。
SetParent((p!=NULL) ? (HWND)(*p) : NULL)
父已正确设置为NULL
或p
取决于这就是我所期待 但是,如果敢偷懒,写:
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;}
}
我怀疑你有Wnd的非显式转换构造太那个需要HWND甚至诠释? 如果是这样,那么明确。
你的Wnd可能没有复制构造函数和operator =声明?声明这些是私人的,不要定义它们。
同时删除operator HWND
并添加成员函数HWND hwnd() const;
您Wnd中。然后代码将看起来像可读:
Setparent(p ? p->hwnd() : NULL);
我相信,当这些MODS完成后,你会发现你的Wnd有什么问题。
的问题表现在,因为两边的操作数:在:必须是同一类型,以便NULL(0)是某种转换为Wnd中。所以* p的临时副本被作为?的返回值:然后运算符HWND被调用。
+1我认为,去除隐式转换从'HWND'到'Wnd'应该做的伎俩,因为这会禁止'NULL'到'Wnd',编译器将被迫向相反的方向转化的转化。无论如何,删除隐式转换将使代码更具可读性和可维护性是完全正确的。 – 2011-05-31 07:44:12
上称为变量p或一些临时变量是p的副本析构函数?
在您的第一个示例中,您正在使用c-style转换将*p
转换为HWND
。第二,您让编译器进行转换,并且可能涉及制作*p
的副本。
?:
操作的操作数必须被带到常见的类型,其将在结果被使用。当您使用
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) {}
...
};
编译器将不再能够使用隐式转换NULL
到Wnd
。在这种情况下,编译器将别无选择地离开,但使用HWND
作为一种常见的,而不是
SetParent(p != NULL ? (HWND) *p : (HWND) NULL);
就像你想它。
P.S.如果您的班级中已有operator HWND() const
,则实施相同的非常量版本operator HWND()
没有意义。
你很可能会需要出示完整的'Wnd'类定义。 – 2011-05-31 00:14:07
@bacchus,注意你的'(HWND))'编辑错了:d虽然改进间距不错... – sarnold 2011-05-31 00:17:18
@sarnold额外的支架是从句子。我错过了。感谢您的警告;) – bacchus 2011-05-31 00:20:57