operator new() behaves differently when operator delete() is deleted depending on the existence of the default constructor
Asked Answered
T

1

16

Creating a new object of class C with operator new() gives an error here:

class C
{
public:
    C() {}
    virtual ~C() {}

    void operator delete(void*) = delete;
};


int main()
{
    C* c = new C;
}

with C2280: 'void C::operator delete(void *)': function was explicitly deleted

But when I replace C() {} with C() = default; or remove the line so that compiler inserts a default constructor(which I believe has the same effect with = default), the code will compile and run.

What are the differences between compiler-generated default constructor and user-defined default constructor that make this happen?

I got some hint in this posting, but class C here(without user-provided constructor) isn't trivial since the destructor is virtual, right?

Compiled with latest Visual Studio, c++17.

Townswoman answered 12/2, 2020 at 9:22 Comment(7)
Not sure, but I think the difference is that the defaulted constructor is noexceptVampirism
Can't reproduce with g++. Similar diagnostic concerning operator delete() whether constructor is manually written or implicitly generated. Which is consistent with my expectations - since an exception may be thrown by the new expression, the compiler needs to access operator delete().Dedal
@SebastianRedl you're right, adding noexcept will make the code compile, but how...?Townswoman
@Dedal The exception can only be thrown by the constructor, so if it is noexcept as SebastianRedl mentioned, then a call to operator delete needn't be included. Also g++ does only complain if the destructor is virtual. Otherwise it always compiles, even if the constructor is throwing.Selfheal
@LeDYoM Your link is about parsing IP addresses, which seems to be irrelevant to the question. Did you post a wrong link?Suppletory
@L.F. You are right. Edited.Madalynmadam
Here is the link: godbolt.org/z/8y23BCMadalynmadam
A
17

What are the differences between compiler-generated default constructor and user-defined default constructor that make this happen?

new expression invokes the corresponding operator new and then calls the constructor. If the constructor throws an exception new expression must undo the effect of operator new (to avoid leaking memory) by calling the corresponding operator delete. If the latter is deleted new expression cannot call it which results in the compiler error: use of deleted function 'static void C::operator delete(void*)'.

A noexcept constructor cannot possibly throw an exception, hence, the corresponding operator delete is not necessary as it won't be called by a new expression. A default constructor of a trivial class is also a noexcept constructor. The presence of a virtual destructor requires operator delete to be non-deleted because the special scalar deleting destructor (an implementation detail to enable delete expression through the base class pointer) invokes operator delete.

It seems to be unspecified by the C++ standard whether the compiler must require operator delete to be non-deleted even if it cannot possibly be called by new expression. gcc, however, doesn't seem to be invoking the corresponding operator delete in new expression at all if it is deleted (posted a bug report).

Aidoneus answered 12/2, 2020 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.