New() Without Delete() Is Undefined Behavior or Merely Memory Leak

new() without delete() is Undefined Behavior or merely Memory Leak?

[basic.life] (3.8 Object lifetime) in paragraph 4 tells :

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined
behavior.

How could pairing new[] with delete possibly lead to memory leak only?

Suppose I'm a C++ compiler, and I implement my memory management like this: I prepend every block of reserved memory with the size of the memory, in bytes. Something like this;

| size | data ... |
^
pointer returned by new and new[]

Note that, in terms of memory allocation, there is no difference between new and new[]: both just allocate a block of memory of a certain size.

Now how will delete[] know the size of the array, in order to call the right number of destructors? Simply divide the size of the memory block by sizeof(T), where T is the type of elements of the array.

Now suppose I implement delete as simply one call to the destructor, followed by the freeing of the size bytes, then the destructors of the subsequent elements will never be called. This results in leaking resources allocated by the subsequent elements. Yet, because I do free size bytes (not sizeof(T) bytes), no heap corruption occurs.

Are memory leaks undefined behavior class problem in C++?

Memory leaks.

There is no undefined behavior. It is perfectly legal to leak memory.

Undefined behavior: is actions the standard specifically does not want to define and leaves upto the implementation so that it is flexible to perform certain types of optimizations without breaking the standard.

Memory management is well defined.

If you dynamically allocate memory and don't release it. Then the memory remains the property of the application to manage as it sees fit. The fact that you have lost all references to that portion of memory is neither here nor there.

Of course if you continue to leak then you will eventually run out of available memory and the application will start to throw bad_alloc exceptions. But that is another issue.

What does the use of new require you to also call delete?

Because that is the way C++ is designed & that is the intended behavior.

The intention was to provide a memory allocation which you demand and own till you reliquish it explicitly.

new gives you a dynamic memory allocation(on heap) which will continue to exist and you own it untill you explicitly deallocate it by calling delete.

Failing to call a delete on a newed buffer will lead to Undefined Behaviors usually in the form of. 1 memory leaks.

1 This was discussed here.

Why is there no memory leak with non-virtual destructor

Because that is how undefined behaviour works. Memory isn't guaranteed to leak. But neither is it guaranteed to not leak. Any behaviour is possible as far as the language is concerned.

why this is Undefined Behaviour

Because a non-virtual destructor is called through a pointer whose dynamic type is of another (derived) type.

whether anything concretely can be said about the lifetime of the B::b

Well, it is a member of B, so it has the same lifetime as any B object. As for the lifetime of the dynamic B object, we cannot really say much due to the UB.

Why is this not a memory leak in C++?

Deleting an object via a polymorphic pointer when the base class doesn't have a virtual destructor is undefined behaviour.

Undefined behaviour may mean your code leaks memory, crashes or works perfectly.

In this case the runtime library presumably allocated a single block of memory for your object and is able to delete that block correctly even when it is pointed to by a pointer of a different type. This is probably true for most runtimes but there are no guarantees. E.g. when using malloc() and free() you don't need to supply the size of the malloc() to free(), the same is happening here.

If you had defined a destructor in Derived you would see that it is not being called.

Can free() cause a memory leak?

Can that cause a memory leak?

In your particular example, no. The x object is merely being allocated by malloc(). free() will correctly deallocate the memory that malloc() allocated. But the object will not be destructed, which is fine in this example because it was not constructed to begin with, so there is nothing to destruct. However, if you try to use that object in any way that expects the constructor to have run, then you end up in undefined behavior territory.

C (where malloc() and free() come from) has no concept of classes, only of memory (de)allocation. C++, on the other hand, has separate concepts of memory (de)allocation and object (de)construction, so you need to be very careful that you use them correctly and not mix them up incorrectly.

If an object were constructed via new, but then deallocated by free() rather than being destructed by delete, the code would definitely have undefined behavior, and if that object had internally allocated any additional memory for itself that the object's destructor is expected to free, that extra memory would be leaked, yes.



Related Topics



Leave a reply



Submit