Is There a Reason to Call Delete in C++ When a Program Is Exiting Anyway

Is there a reason to call delete in C++ when a program is exiting anyway?

It is important to explicitly call delete because you may have some code in the destructor that you want to execute. Like maybe writing some data to a log file. If you let the OS free your memory for you, your code in your destructor will not be executed.

Most operating systems will deallocate the memory when your program ends. But it is good practice to deallocate it yourself and like I said above the OS won't call your destructor.

As for calling delete in general, yes you always want to call delete, or else you will have a memory leak in your program, which will lead to new allocations failing.

Must new always be followed by delete?

There is nothing that requires a delete[] in the standard - However, I would say it is a very good guideline to follow.

However, it is better practice to use a delete or delete[] with every new or new[] operation, even if the memory will be cleaned up by the program termination.

Many custom objects will have a destructor that does other logic than just cleaning up the memory. Using delete guarantees the destruction in these cases.

Also, if you ever move around your routines, you are less likely to cause memory leaks in other places in your code.

should i call delete or destructor is enough in c++

if within a function, i new up an object, should i call delete on the pointer before exit of the function or would destructor, which would be automatically called after function exits, do the job of delete?

When returning from a function, all the local objects with automatic storage duration are destroyed. If they are of a class type, their destructor gets invoked before the storage they occupied is claimed back. If they are of a non-class type (like int), there is no destructor to invoke.

Here, the only local object with automatic storage duration is the pointer a (beware: not the object pointed to by a!), and pointers are not of a class type. This means that a will be destroyed, and that's it - in particular, the object a points to will not be destroyed.

Therefore, you have to call delete before you leave the function (no matter whether you leave it by doing return or by throwing an exception). In general, you always have to match each call to new with a call to delete, and each call to new[] with a call to delete[].

Since it is easy to forget about calling delete (as it is easy to call it more than once!) after having created an object with new, it is good practice in Modern C++ to use so-called RAII wrappers (such as smart pointers), which are local objects whose destructors are meant to clean up the resources acquired during construction.

For instance:

void foo()
{
auto p = std::make_unique<A>(); // OK, make_unique() will only be available
// in C++14. Meanwhile, in C++11 you can do:
//
// std::unique_ptr<A> p(new A());

// Work with p...

// No memory leak here!
}

In case you are not allowed to use C++11, for instance because your boss says the SW must compile on older versions of your compiler for compatibility reasons, you can always kill your boss use Boost's smart pointer classes such as boost::shared_ptr and boost::scoped_ptr.

Notice, anyway, that you should not perform a dynamic allocation unless you need to. If you do not need it (e.g. if you don't have to share the ownership of that object with any other function), you can simply give your A object automatic storage duration, thus ensuring its destructor will be invoked when it goes out of scope:

void foo()
{
A a;

// Work with a...

// a will be destroyed when returning from foo()
}

Should I delete big tree collections in C++ at the end of program or leave that to OS?

There is no guarantee in the C and C++ standards of what happens after your program exits. Including no guarantee that anything is cleaned up. Some smaller real-time OS' for example, will not perform automatic cleanup. So at least in theory, your program should definitely do delete everything you new to fulfil it's obligation as a complete and portable program that can run forever.

It is also possible that someone takes your code and puts a loop around it, so that your tree is now created a million times, and then goes to find you, bringing along the "trusty convincer", aka base-ball bat, when they find out WHY it's now running out of memory after 500 iterations.

Of course, like all things, this can be argued many different ways, and it really depends on what you are trying to achieve, why you are writing the program etc. My compiler project leaks memory like a sieve, because I use exactly the method of memory management that you describe (partly because tracking the lifetime of each dynamically allocated object is quite difficult, and partly because "I can't be bothered". I'm sure if someone actually wants a good pascal compiler, they won't go for my code anwyay).

Actually, my compiler project builds many different data structures, some of which are trees, arrays, etc, but basically none of them perform any cleanup afterwords. It's not as simple to fix as the case of building a large tree that need each node deleting. However, conceptually, it all boils down to "do cleanup" or "not do cleanup", and that in turn comes down to "well, who is going to use/modify the code, and what do you know about the environment it will run in".

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.

free/delete - what if I don't call them

Whether the memory leaks or not depends on the Operating system. In case of most operating systems once the process in which your program runs exits the OS simply reclaims back the memory it allocated to the process.

There is another important aspect to it. new results in calling of the class constructor and delete results in call to an destructor. So if you called new and never called delete then in addition to the so called memory leak which may/may not exist after the program exit there is an additional condition that if the destructor of the particular class invokes some code which has side effects then it results in Undefined Behavior.

So the answer is it depends, You may possibly have:

  • A memory leak(depending on the OS behavior)
  • An undefined behavior(depending on whether code in destructor has side effects)

C++11 Standard 3.8 Object lifetime:

Para 4:

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.

Why do I have to call delete twice when I have each two pointers at same memory?

When I did delete k, however, the k and d point the memory yet.

Invoking operator delete on some pointer will ask the operating system to release the memory associated with this pointer, but doesn't change the value of the pointer itself. k and d simply continue pointing to that same location in memory, which is released in the mean time.

That's why sometimes people set a pointer to nullptr after delete-ing it. In your case, this would have saved you from undefined behavior:

delete d;

d = nullptr;
k = nullptr; // Both must be re-assigned

delete k; // Ok, delete on a nullptr is a no-op


Related Topics



Leave a reply



Submit