Why is the delete operator required to be static? - c++

I found this one question asking the same thing, however only the 'new' part was answered, so here goes again.
Why is the delete operator required to be static? Somehow it doesn't make sense. The new operator makes perfect sense, just like the constructor can't be virtual, neither can the new operator. However, the destructor can (and should) be virtual when you use inheritance, in order to allow destruction of objects being used (by way of polymorphism) as a base class.
I understand that, when the delete operator is called, the object has already been destroyed, so no 'this' exists. Yet it still makes sense, using the same reasoning as with virtual destructor, to have the delete operator match the new operator which created the object.
This is what I mean
class A
{
public:
virtual ~A() {}
};
class B : public A
{
public:
void* operator new (size_t sz);
void operator delete (void* ptr, size_t sz);
};
now if we do
A *ptr = new B();
delete ptr; // <-- fail
A's delete operator (default) should've been called, since it's static and it's not known (for anything but the trivial case here) at compile time which delete-operator is the correct one.
However, I made a small test program with the code above (just malloc/free in the new/delete operators, and print statement in delete), and compiled it using g++. Running it quite unexpectedly produced the output in B's delete operator.
My (real) question is this: Is there some implicit 'virtualness' to the delete operator? Is it only static in the no-this-pointer sense? Or is this just a g++ feature?
I started looking through the C++ specification, but I must admit, I was bit overwhelmed by it, so any help appreciated.

The answer in the language rules is really in 12.5 [class.free].
If you are deleting via a pointer to a base class then the destructor must be virtual or you get undefined behaviour. Otherwise, the implementation has to determine the dynamic type of the object being deleted.
12.5/4 says that when the delete isn't prefixed by :: then the deallocation function is determined by looking up delete in the context of the dynamic type's virtual destructor. This ensures virtual-like lookup, even though operator delete is always a static member function.
Raw allocation and deallocation happen conceptually outside of the object's lifetime so by the time the deallocation function is to be called, there is no longer an object to provide a virtual lookup mechanism but the lookup rules ensure that operator delete has a dynamic (virtual-lite!) lookup mechanism. This means that operator delete can sensibly be static without losing touch with the original object's dynamic type.

delete operator is for deallocating memory only, and memory is deallocated for the most derived class object as a whole - in one action - exactly the same way as with new operator it is allocated for the whole most-derived class object - the object of class passed as argument into new Class construct.
This is why when you do delete ptr; the delete operator is always called only once for the actual most-derived class of the object being deleted and the data on what class it is is deduced from either the vtable if the virtual destructor is present or the type of the pointer if there's no virtual destructor. That's why there'no implicit virtualness to the delete operator - all virtualness ends at the point of destructor call.

Related

Is a member pointer defined with 'new' in the header file a memory leak?

In code I use I found a class declaration in a header file that contains a pointer to const as a member that is defined with 'new' right there in the header file.
A matching 'delete' is in the destructor (also defined right there in the header).
Is this usage ok? Does it create a memory leak?
The destructor is called only when an object of that class is destroyed, either by a delete (when created with new) or by going out of scope (when created on the stack).
But the 'new' is not in the constructor, but part of the class declaration. Isn't this executed earlier? Maybe even whenever the header is parsed? Is it guaranteed to me matched by the delete in the destructor?
class Foo {
public:
explicit Foo(){}
~Foo() {
delete this->bar;
}
private:
const Baz* bar = new Baz();
};
Does it create a memory leak?
Potentially, yes. If you assign to an instance of Foo, the memory owned by the previous pointer value is leaked.
Isn't this executed earlier? Maybe even whenever the header is parsed?
No. Members are initialized by a constructor. The default member initialiser in the declaration of the member is used if the constructor doesn't specify a member initialiser explicitly (such as is the case for the constructor you declared).
Is this usage ok? Is it guaranteed to me matched by the delete in the destructor?
No. Besides the leak, if you make a copy of the object, there will be two deletes matching only one new. The program would have undefined behaviour.
The simplest fix for both the leak, and UB is to use std::unique_ptr instead of a bare pointer. (Or possibly std::shared_ptr in case you want the class to be copyable, and want the copies to share the ownership of the same Baz object).
There is no problem with the default member initialiser though. The problems mentioned above are with lack of class invariants that are necessary when dealing with resource acquisition.

C++: delete with placement parameter [duplicate]

Why C++ hasn't placement delete that directly corresponds to the placement new, i.e. calls the destructor and calls appropriate placement delete operator?
For example:
MyType *p = new(arena) MyType;
...
//current technique
p->~MyType();
operator delete(p, arena);
//proposed technique
delete(arena) p;
operator delete is unique in being a non-member or static member function that is dynamically dispatched. A type with a virtual destructor performs the call to its own delete from the most derived destructor.
struct abc {
virtual ~abc() = 0;
};
struct d : abc {
operator delete() { std::cout << "goodbye\n"; }
};
int main() {
abc *p = new d;
delete p;
}
(Run this example.)
For this to work with placement delete, the destructor would have to somehow pass the additional arguments to operator delete.
Solution 1: Pass the arguments through the virtual function. This requires a separate virtual destructor for every static member and global operator delete overload with different arguments.
Solution 2: Let the virtual destructor return a function pointer to the caller specifying what operator delete should be called. But if the destructor does lookup, this hits the same problem of requiring multiple virtual function definitions as #1. Some kind of abstract overload set would have to be created, which the caller would resolve.
You have a perfectly good point, and it would be a nice addition to the language. Retrofitting it into the existing semantics of delete is probably even possible, in theory. But most of the time we don't use the full functionality of delete and it suffices to use a pseudo-destructor call followed by something like arena.release(p).
Probably because there was syntax for explicitly calling a destructor without deallocation (exactly as in your question), but no syntax for explicit construction in raw memory?
Actually there is a placement delete which is called by the implementation for an object that was "allocated" using placement new if the constructor threw an exception.
From Wikipedia.
The placement delete functions are called from placement new expressions. In particular, they are called if the constructor of the object throws an exception. In such a circumstance, in order to ensure that the program does not incur a memory leak, the placement delete functions are called.
The whole point of placement new is to separate object creation from its memory management. So it makes no sense to tie it back during object destruction.
If memory for your objects is from heap and you want same lifetime for objects and their memory just use operator new and operator delete, maybe overriding them if you want any special behavior.
Placement new is good for example in vector, which keeps a large chunk of raw memory and creates and destroys object inside of it, but without releasing memory.

Virtual destructor and memory deallocation

I'm not quite sure I understand virtual destructors and the concept of allocating space on the heap right. Let's look at the following example:
class Base
{
public:
int a;
};
class Derived : public Base
{
public:
int b;
};
I imagine that if I do something like this
Base *o = new Derived;
that 8 Bytes (or whatever two integers need on the system) are allocated on the heap, which looks then something like this:
... | a | b | ...
Now if I do this:
delete o;
How does 'delete' know, which type o is in reality in order to remove everything from the heap? I'd imagine that it has to assume that it is of type Base and therefore only deletes a from the heap (since it can't be sure whether b belongs to the object o):
... | b | ...
b would then remain on the heap and be unaccessible.
Does the following:
Base *o = new Derived;
delete o;
truly provoke memory leaks and do I need a virtual destructor here? Or does delete know that o is actually of the Derived class, not of the Base class? And if so, how does that work?
Thanks guys. :)
You're making a lot of assumptions about the implementation, which may
or may not hold. In a delete expression, the dynamic type must be the
same as the static type, unless the static type has a virtual
destructor. Otherwise, it is undefined behavior. Period. That's
really all you have to know—I've used with implementations where
it would crash otherwise, at least in certain cases; and I've used
implementations where doing this would corrupt the free space arena, so
that the code would crash sometime later, in a totally unrelated piece
of code. (For the record, VC++ and g++ both fall in the second case, at
least when compiled with the usual options for released code.)
Firstly, the classes you declared in your example have trivial internal structure. From purely practical point of view, in order to destroy object of such classes properly the run-time code does not need to know the actual type of the object being deleted. All it needs to know is the proper size of the memory block to be deallocated. This is actually something that is already achieved by C-style library functions like malloc and free. As you probably know, free implicitly "knows" how much memory to deallocate. Your example above does not involve anything in addition to of that. In other words, your example above is not elaborate enough to truly illustrate anything C++-specific.
However, formally the behavior of your examples is undefined, since virtual destructor is formally required by C++ language for polymorphic deletion regardless of how trivial the internal structure of the class is. So, your "how delete knows..." question simply does not apply. Your code is broken. It does not work.
Secondly, the actual tangible C++-specific effects begin to appear when you begin to require non-trivial destruction for your classes: either by defining an explicit body for the destructor or by adding non-trivial member subobjects to your class. For example, if you add a std::vector member to your derived class, the destructor of the derived class will become responsible for (implicit) destruction of that subobject. And in order for that to work, you will have to declare you destructors virtual. A proper virtual destructor is called through the same mechanism as any other virtual function is called. That's basically the answer to your question: the run-time code does not care about the actual type of the object simply because the ordinary virtual dispatch mechanism will ensure that the proper destructor is called (just like it works with any other virtual function).
Thirdly, another significant effect of virtual destruction appears when you define dedicated operator delete functions for your classes. The language specification requires that the proper operator delete function is selected as if it is looked up from inside the destructor of the class being deleted. And many implementations implement this requirement literally: they actually implicitly call operator delete from inside the class destructor. In order for that mechanism to work properly, the destructor has to be virtual.
Fourthly, a part of your question seems to suggest that you believe that failing to define a virtual destructor will lead to "memory leaks". This a popular, but completely incorrect and totally useless urban legend, perpetuated by low-quality sources. Performing polymorphic deletion on a class that has no virtual destructor leads to undefined behavior and to completely unpredictable devastating consequences, not to some "memory leaks". "Memory leaks" are not the issue in such cases.
There is no problem in the size of the object being deleted - it is known. The problem solved by virtual destructors can be demonstrated as follows:
class Base
{
public:
Base() { x = new char[1]; }
/*virtual*/ ~Base() { delete [] x; }
private:
char* x;
};
class Derived : public Base
{
public:
Derived() { y = new char[1]; }
~Derived() { delete [] y;}
private:
char* y;
};
Then having:
Derived* d = new Derived();
Base* b = new Derived();
delete d; // OK
delete b; // will only call Base::~Base, and not Derived::~Derived
The second delete will not finalize the object properly. If the virtual keyword was uncommented, then the second delete statement will behave as expected, and it will call Derived::~Derived along with Base::~Base.
As pointed out in the comments, to be strict, the second delete yields an undefined behavior, but it's used here only for the sake of making the point about virtual destructors.

Unable to nail memory leak detected by valgrind

Below is the pattern of new/delete operators in my program. Valgrind says that memory is "definitely lost". I couldn't quite get where the leak is. Is there something wrong with my usage of new/delete operators.
class Generic
{
GenericInterface *gInterface; //GenericInterface is abstract class
public:
Generic ()
{
gInterface = NULL;
}
~Generic ()
{
delete gInterface;
}
void Create()
{
gInterface = new Specific();
}
};
class Specific : public GenericInterface
{
MyClass* _myClass;
public:
Specific()
{
_myClass = new MyClass;
}
~Specific()
{
delete _myClass;
}
};
int main()
{
Generic g;
g.Create();
}
valgrind says that memory is lost.
==2639== 8 bytes in 1 blocks are definitely lost in loss record 2 of 45
==2639== at 0x4026351: operator new(unsigned int) (vg_replace_malloc.c:255)
==2639== by 0x804D77C: Specific::Specific() (Specific.cc:13)
==2639== by 0x804DAFC: Generic::Create() (Generic.cc:58)
You are not following the rule of three. If your class manages resources that need to be cleaned up, you must declare a destructor, copy constructor, and copy assignment operator. Neither of your classes has a copy constructor or a copy assignment operator.
Really, you should almost certainly just be using a smart pointer like unique_ptr from C++0x; shared_ptr from Boost, C++ TR1, and C++0x; or scoped_ptr from Boost.
The likely issue causing this specific problem is that you have forgotten to make the base-class GenericInterface destructor virtual, so the wrong destructor is being called and the MyClass object that you dynamically create in Specific is never destroyed.
deleteing an object via a pointer to one of its base classes results in undefined behavior if the base class destructor is not declared virtual (that means bad things will happen, ranging from memory leaks to crashes).
Your GenericInterface destructor probably is not virtual, so only the GenericInterface destructor is getting called when gInterface is destroyed.
Does your GenericInterface class declare a virtual destructor? If not, the Specific class's destructor won't get called, and thus the "delete _myClass" line won't be executed.
Just another way C++ makes your life more interesting :)
In your Generic class destructor you should also check the gInterface pointer before deleting it. If Create() is not called before the object is destroyed it will cause problems. If your c++ compiler doesn't throw on new failures your other class may also do the same thing

Is the whole object freed with a non-virtual destructor and a Base class pointer?

If a Base class does not have a virtual destructor (in order to avoid the vtable entry for instance) and the Derived class has only basic attributes, does it free all the memory allocated by new, when the pointer of the Base class is deleted? I know the destructor of the Derived class will not be called but I am wondering if the memory allocated by the whole object will be freed?
I assume also that calling delete on a Derived pointer will free the whole memory space.
Also, if it does not free the Derived class part of the memory, how does it work in the same case but with of a virtual destructor in the Base class, to know how much memory to free?
Example:
class Base {
public:
int a;
int b;
Base() {}
~Base() {}
};
class Derived : public Base {
public:
int c;
int d;
Derived() {}
~Derived() {}
};
int main() {
Base *p = new Derived();
delete p; // is memory allocated for Derived freed?
}
It's undefined behavior, so anything can happen. Quote from the standard [expr.delete]:
In the first alternative (delete object), if the static type of the object
to be deleted is different from its
dynamic type, the static type shall be
a base class of the dynamic type of
the object to be deleted and the
static type shall have a virtual
destructor or the behavior is
undefined.
Just don't do that.
I think it's a good idea to understand what actually happens though to understand why the standard has that requirement.
In your simple case, on a typical implementation, the memory will be freed regardless. That is because operator delete will call free(p). Since Base is the first non-virtual base class of Derived, it happens to be located at the beginning of the allocated memory block. And since free must know the size of the allocated block by its own bookkeeping (being a C function it doesn't know anything about sizes of types), it will deallocate the entire block.
However, since Base doesn't have a virtual destructor, delete p is resolved based on the static-type of *p (which is Base). Consequently, as you're seemingly aware, it will not call the destructor of Derived. If Derived had any non-trivial members or base-classes, those would not be destructed either, so any resources that they manage would be leaked.
When the class has a virtual destructor, the work of freeing the memory is delegated to the destructor. The reason is that, although free knows to determine the size of the block, it would still need to have the pointer to the beginning of it. Base can be at an arbitrary offset within Derived in the general case, therefore Derived destructor will be responsible for adjusting the pointer prior to freeing it. This also adds the need for a separate destructor that would destructor the object without actually freeing the memory; e.g. as a subobject of another derived type, or as explicit destructor call. And let's keep delete[] out of the discussion. When you mark your destructor as virtual, the compiler takes care of all this for you.
The bottom line is that the standard doesn't describe all these implementation details, leaving them instead to—um—the implementation. They could formulate some sensible criteria when deleting a non-virtual base would still be ok; but instead they went with the simple clear-cut "you have a virtual destructor then it's ok, otherwise it's not ok" rule.
Technically, the answer is 'unknown'. Deleting a pointer to derived from a pointer to base that has no virtual destructor is undefined behavior.
Practically speaking though, most implementations just fail to properly delete the stuff in the derived object.
Formally speaking, this is undefined behaviour, so you have no guarantees that the memory is freed, or indeed that your program does anything in particular. It may format your hard disk. It may not. In practice, the memory might well be freed in this case -- but you're daft if you rely on it, and you shouldn't do it. It's as simple as that.
Edit: I Was mistaken: Key prose from draft standard, emphasis mine: Section 5.3.5
3 In the first alternative (delete
object), if the static type of the
object to be deleted is different from
its dynamic type, the static type
shall be a base class of the dynamic
type of the object to be deleted and
the static type shall have a virtual
destructor or the behavior is
undefined. In the second alternative
(delete array) if the dynamic type of
the object to be deleted differs from
its static type, the behavior is
undefined.
There is a good chance the memory will be correctly freed. Just because the Standard doesn't assure this doesn't mean it won't work. It's hard to see how it could fail.
In the very particular case that you describe, all of the memory used by the derived class object will be freed when you don't have a virtual destructor. (If using non-virtual destructors always caused derived classes to leak memory, I don't think the language would allow inheriting from classes that used them!)
Remember, the DESTRUCTOR is not what frees the memory; "delete" frees the memory. The destructor is just a function that gets CALLED by delete.
Blah blah blah extensibility blah blah cause yourself trouble in the future blah blah careful with that etc. etc. etc. You know what I mean, obviously.