条件运算符 ? 的限制:

发布于 2024-11-10 13:25:11 字数 1043 浏览 12 评论 0原文

我正在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我也只是我 2024-11-17 13:25:11

我怀疑你的 Wnd 也有非显式转换构造函数,它需要 HWND 甚至 int ?
如果是这样,请明确说明。

您的 Wnd 可能没有声明复制构造函数和运算符=?将它们声明为私有并且不定义它们。

同时删除 operator HWND 并将成员函数 HWND hwnd() const; 添加到您的 Wnd 中。然后代码将看起来可读如下:

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

我相信当这些 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 function HWND hwnd() const; to your Wnd. Then the code will look readable like:

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

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.

弱骨蛰伏 2024-11-17 13:25:11

析构函数是在变量 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 a HWND. In the second, you are letting the compiler do the conversion, and that might well involve making a copy of *p.

不奢求什么 2024-11-17 13:25:11

?: 运算符的操作数必须为通用类型,该类型将在结果中使用。当您使用时

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));

I.e.当 p 为 null 时,编译器会构造一个临时对象 Wnd(NULL) (使用您提供的转换构造函数)并将其作为结果返回。此外,编译器很可能也会在 true 分支中构造一个临时对象(通过使用复制构造函数)。然后将生成的临时对象转换为 HWND 类型(因为这是 SetParent 所需要的),因此整个事情被解释为

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

临时对象在调用后立即被销毁到SetParent。这是您观察到的破坏,只是您错误地将其解释为 p 的破坏。

编译器可以选择此方法的原因是您的转换构造函数未显式声明。如果您显式声明转换构造函数,

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

编译器将无法再使用它来将NULL隐式转换为Wnd。在这种情况下,编译器将别无选择,只能使用 HWND 作为通用类型,而不是

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

像您希望的那样。

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 use

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

you essentially manually force the situation, when the compiler has choose the common type to be HWND. I.e. the above variant is equivalent to

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

But when you do

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

the rules of the language work differently, the compiler will decide the common type differently. In this the common type is not HWND, but your Wnd. Both operands are converted to Wnd and the latter variant is interpreted as

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

I.e. when p is null the compiler constructs a temporary object Wnd(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 to HWND type (since that is what SetParent requires), so the whole thing is interpreted as

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

The 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 of p.

The reason the compiler can choose this approach is because your conversion constructor is not declared explicit. If you declare the conversion constructor explicit

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

the compiler will no longer be able to use to implicitly convert NULL to Wnd. In that case the compiler will be left with no choice but to use HWND as a common type instead

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

just 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 version operator HWND().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文