3

Consider the following code:

class Base {
public:
#ifdef __VIRTUAL__
   virtual ~Base() {}
#else
   ~Base() {}
#endif
};

class Derived : public Base {
public:
    ~Derived() {}
private:
    static void operator delete(void*) = delete;
};

int main() {
    Derived d;
}

It'll compiled successfully with cmd

g++ -std=c++11 main.cpp

but failed with cmd

g++ -std=c++11 -D__VIRTUAL__ main.cpp

The output shows the operator delete is required

main.cpp: In destructor ‘virtual Derived::~Derived()’:
main.cpp:12:17: error: use of deleted function ‘static void Derived::operator delete(void*)’
     ~Derived() {}
                 ^
main.cpp:14:17: error: declared here
     static void operator delete(void*) = delete;
                 ^
main.cpp: In destructor ‘virtual Derived::~Derived()’:
main.cpp:12:17: error: use of deleted function ‘static void Derived::operator delete(void*)’
     ~Derived() {}
                 ^
main.cpp:14:17: error: declared here
     static void operator delete(void*) = delete;
                 ^

It means that if I use virtual destructor function, I cannnot delete operator delete .

Why is this happened, why virtual destructor required global operator delete even if created on stack.

libgcc
  • 153
  • 3
  • 7
  • I'm more curious about your use-case for possibly *not* wanting the `Base` constructor to be virtual? And why you need to mark the `delete` operator as deleted for the `Derived` class? What is the *actual* problem you need to solve? – Some programmer dude Jul 08 '19 at 03:18
  • @Someprogrammerdude The code is croped and reshapred from my working copy. I just need to create a QDialog's subclass and prevent the creation on heap, so I delete the global operator new and operator delete, then gcc complained. BTW, msvc2017 doesn't – libgcc Jul 08 '19 at 03:25
  • Because the destructor must know how to deallocate the object, even if you are not using free store in your particular program. – n. m. could be an AI Jul 08 '19 at 03:29
  • 1
    For all the compiler knows, another source file does `Base* p = new Derived(); delete p;` For this to work, the knowledge of the overloaded `operator delete` has to be baked into the virtual destructor. It is while doing the baking that the compiler discovers, and complains about, the deleted `operator delete`. – Igor Tandetnik Jul 08 '19 at 03:46
  • but failed... what is the error message please? – alfC Jul 08 '19 at 03:54
  • @libgcc: "*prevent the creation on heap*" Deleting `operator delete` will in no way stop users from putting it on the heap. Placement `new` and direct calls to the destructor are available. Indeed, there is pretty much *nothing* in C++ you can do to stop that, short of making the object non-constructible. It's best to just put a warning in your code and accept that some people will break it, assuming you have legitimate reasons for forbidding heap allocation to begin with. – Nicol Bolas Jul 08 '19 at 04:07
  • @alfC the output is added on – libgcc Jul 08 '19 at 08:42

1 Answers1

2

The operator delete function is only called during deletion of an object with dynamic storage duration. It's not called by your program.

However, the standard requires that this function be available if there is a virtual destructor, even if the object is never actually used dynamically.

In the C++17 standard this is [class.dtor]/13:

At the point of definition of a virtual destructor (including an implicit definition), the non-array deallocation function is determined as if for the expression delete this appearing in a non-virtual destructor of the destructor’s class. If the lookup fails or if the deallocation function has a deleted definition, the program is ill-formed. [Note: This assures that a deallocation function corresponding to the dynamic type of an object is available for the delete-expression. —end note ]

Why does the standard require this? I have no idea but you're going to have to find some other approach to solve your problem. Maybe this thread will be useful: Any way to prevent dynamic allocation of a class?

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I know, my problem is easy to solve, only delete the `operator new` will working. I just wonder why `operator delete` is necessary and why the standard require this. Why msvc doesn't complain about it ? – libgcc Jul 08 '19 at 08:38
  • 1
    @libgcc if MSVC doesn't complain , in conforming mode, then it's a compiler bug – M.M Jul 08 '19 at 08:41