从重载运算符删除中调用成员函数?

时间:2011-03-25 20:04:45

标签: c++ memory-management operator-overloading

Binary-compatible C++ Interfaces上的这篇文章包含代码:

class Window {
public:
  // ...
  virtual void destroy() = 0;

  void operator delete(void* p) {
    if (p) {
      Window* w = static_cast<Window*>(p);
      w->destroy(); // VERY BAD IDEA
    }
  }
};

对我来说,这似乎是错误的:operator delete()适用于原始内存,目的是释放它。已经调用了对象的析构函数,因此调用destroy()可以处理“幻像”对象(如果它可以正常工作)。确实:这就是为什么operator delete()需要void*而不是Window*(在这种情况下)。

所以,设计存在缺陷,对吧? (如果它是正确的,为什么是正确的?)

3 个答案:

答案 0 :(得分:6)

我同意(假设Window::destroy不是静态成员函数):

  

3.8p1:类型为T的对象的生命周期结束时:如果T是具有非平凡析构函数的类类型,则析构函数调用开始,或者[...] < / p>      

3.8p5:[...]在对象的生命周期结束之后,在重用或释放对象占用的存储之前,任何指向对象所在的存储位置的指针可以使用但仅限于有限的方式。 ...如果对象将是或者是非POD类类型,则程序具有未定义行为,如果:指针用于访问非静态数据成员或调用非静态数据成员对象的成员函数,或[...]

(强调我的)

答案 1 :(得分:0)

是的,该代码(如果标记为C ++)是非常错误的。

运算符new和delete,就像你说的那样处理原始内存,而不是对象。

然而,那篇文章涉及特定的编译器和具体的实现问题,所以可能是在那个受限制的上下文中代码可以运行...而且MS并不是因为它们对可移植C ++的关注程度非常出名(确实是相反的)所以可能那种糟糕的代码(或者在2002年)实际上不仅工作,而且甚至是合理的解决方案。

答案 2 :(得分:0)

这是非常讨厌的代码,试图提供帮助。

文章说在COM代码中不应该delete对象,而是调用obj->destroy()。所以为了“有用”,作者让操作员删除做破坏调用。讨厌!

更好的方法就是声明私有操作符删除,因此用户无法删除对象,而必须找出正确的方法。