条件运算符 ? 的限制:
我正在使用 GCC 4.5,并观察到非常奇怪的行为。我想知道这个运算符是否有一些我不完全理解的地方。我以为我精通C++。 我有一个针对 Windows HWND
对象的瘦 C++ 包装类 Wnd
,并带有已实现的强制转换运算符 operator HWND ...
。
如果我使用这样的条件运算符(给定输入 Wnd *p
和示例函数 SetParent(HWND))
:
SetParent((p!=NULL) ? (HWND)(*p) : NULL)
父项已正确设置为 NULL
code> 或 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;}
}
I am using GCC 4.5 and have observed very peculiar behavior. I am wondering if there is something with this operator that I do not completely understand. I thought I was proficient in C++.
I have a thin C++ wrapper class Wnd
for Windows HWND
objects with an implemented cast operator operator HWND ...
.
If I use the conditional operator like this (given input Wnd *p
and a sample function SetParent(HWND))
:
SetParent((p!=NULL) ? (HWND)(*p) : NULL)
The parent is properly set to NULL
or p
depending. This is what I would expect.
However if dare to be lazy and write:
SetParent(p ? *p : NULL)
things go haywire.
After running GDB I find that destructor is called on variable p
after the call to 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;}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我怀疑你的 Wnd 也有非显式转换构造函数,它需要 HWND 甚至 int ?
如果是这样,请明确说明。
您的 Wnd 可能没有声明复制构造函数和运算符=?将它们声明为私有并且不定义它们。
同时删除
operator HWND
并将成员函数HWND hwnd() const;
添加到您的 Wnd 中。然后代码将看起来可读如下:我相信当这些 mods 完成后你会发现你的 Wnd 有什么问题。
问题本身就出现了,因为 : in ?: 两边的操作数必须是相同的类型,因此 NULL (0) 可以以某种方式转换为 Wnd。因此 *p 的临时副本被制作为 ?: 的返回值,然后对其调用运算符 HWND。
I suspect that your Wnd has non-explicit conversion constructor too that takes HWND or even int?
If so then make it explicit.
Your Wnd probably does not have copy constructor and operator= declared? declare these private and don't define them.
Also remove
operator HWND
and add member functionHWND hwnd() const;
to your Wnd. Then the code will look readable like:I trust that when these mods are done you will find out what is wrong with your Wnd.
The problem manifests itself because the operands at both sides of : in ?: have to be of same type so NULL (0) is somehow convertible to Wnd. So the temporary copy of *p is made as return value of ?: then operator HWND is called to it.
析构函数是在变量 p 上调用还是在某个作为 p 副本的临时变量上调用?
在第一个示例中,您使用 c 风格转换将
*p
转换为HWND
。在第二种情况下,您让编译器进行转换,这很可能涉及制作*p
的副本。Is the destructor called on variable p or on some temporary variable that is a copy of p?
In your first example you are using c-style cast to convert
*p
to aHWND
. In the second, you are letting the compiler do the conversion, and that might well involve making a copy of*p
.?:
运算符的操作数必须为通用类型,该类型将在结果中使用。当您使用时,当编译器选择通用类型为
HWND
时,您本质上是手动强制这种情况。即上面的变体相当于但是当你以
不同的方式执行语言工作的规则时,编译器将不同地决定公共类型。在此,常见类型不是
HWND
,而是您的Wnd
。两个操作数都转换为Wnd
,后一个变体被解释为I.e.当
p
为 null 时,编译器会构造一个临时对象Wnd(NULL)
(使用您提供的转换构造函数)并将其作为结果返回。此外,编译器很可能也会在 true 分支中构造一个临时对象(通过使用复制构造函数)。然后将生成的临时对象转换为HWND
类型(因为这是SetParent
所需要的),因此整个事情被解释为临时对象在调用后立即被销毁到
SetParent
。这是您观察到的破坏,只是您错误地将其解释为p
的破坏。编译器可以选择此方法的原因是您的转换构造函数未
显式
声明。如果您显式
声明转换构造函数,编译器将无法再使用它来将
NULL
隐式转换为Wnd
。在这种情况下,编译器将别无选择,只能使用 HWND 作为通用类型,而不是像您希望的那样。
PS:当您的类中已经有
operator HWND() const
时,实现相同的非 const 版本operator HWND()
是没有意义的。The operands of
?:
operator must be brought to common type, which will be used at the result. When you useyou essentially manually force the situation, when the compiler has choose the common type to be
HWND
. I.e. the above variant is equivalent toBut when you do
the rules of the language work differently, the compiler will decide the common type differently. In this the common type is not
HWND
, but yourWnd
. Both operands are converted toWnd
and the latter variant is interpreted asI.e. when
p
is null the compiler constructs a temporary objectWnd(NULL)
(using the conversion constructor you provided) and returns it as the result. Moreover, the compiler will most likely construct a temporary object in the true branch too (by using the copy constructor). The resultant temporary object is then converted toHWND
type (since that is whatSetParent
requires), so the whole thing is interpreted asThe temporary object is then destroyed immediately after the call to
SetParent
. This is the destruction that you observed, except that you incorrectly interpreted it as the destruction ofp
.The reason the compiler can choose this approach is because your conversion constructor is not declared
explicit
. If you declare the conversion constructorexplicit
the compiler will no longer be able to use to implicitly convert
NULL
toWnd
. In that case the compiler will be left with no choice but to useHWND
as a common type insteadjust like you wanted it to.
P.S. When you already have
operator HWND() const
in your class, there's no point in implementing the identical non-const versionoperator HWND()
.