C++ Is It Necessary to Delete Dynamically Allocated Objects at the End of the Main Scope

C++ is it necessary to delete dynamically allocated objects at the end of the main scope?

Most of the modern OS always reclaim back all memory they allocated to a program(process).

The OS doesn't really understand if your program leaked memory it merely takes back what it allocatted.

But there are bigger issues at hand than just the memory loss:

Note that if the destructor of the object whos delete needs to be called performs some non-trivial operation and your program depends on the side effects produced by it then your program falls prey to Undefined Behavior[Ref 1]. Once that happens all bets are off and your program may show any beahvior.

Also, An OS usually reclaims the allocated memory but not the other resources, So you might leak those resources indirectly. This may include operations dealing with file descriptors or state of the program itself etc.

Hence, it is a good practice to always deallocate all your allocations by calling delete or delete [] before exiting your program.


[Ref 1]C++03 Standard 3.8 Para 4:

"....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."

Is it safe to delete an object having a dynamically allocated block using delete keyword

If you have something like this:

class Foo
{
public:
int* block;

Foo()
{
block = new int[10];
}

private:
Foo(const Foo&);
Foo& operator =(const Foo&);
};

And subsequently do this:

Foo* foo = new Foo;
delete foo;

Then yes, you're leaking memory. The dynamic block in your Foo object is never released. You can address this with a destructor that releases it. (of source, you need to declare the destructor in the class declaration as well):

Foo::~Foo()
{
delete [] block;
}

I would advise you to do two things

  1. Count the delete's and the new's. if they're not the same, thats generally a problem.
  2. Read this informative document on dynamic pointer and memory usage with C++.

Following #2, btw, might give you an object that looks similar to this:

class Foo
{
public:
std::array<int,10> block;

Foo() // note: default-construction of `block`
{
}

// note: default *destructor* will clean up member variables
// by firing their destructors for you. in this case the destructor
// for our 'block' member is a std::array that knows how to self-clean.

// note: we no longer have to hide or implement copy construction and
// assignment operator functionality. The default implementation of
// these properly member-copy and member-assign respectively.
};

And a usage (one of many possibilities) like this:

std::unique_ptr<Foo> foo(new Foo);

Please regard the notes in the source of the last example. There is a tremendous weight lifted off your memory-management shoulders by using classes that practice self-managed members. In lifting that weight, so too goes the per-chance likelihood of introducing bugs related to it, like memory leaks, shallow-copy perils, etc.

How do I destruct a dynamically allocated array of dynamic object?

Is it necessary to delete all the objects in the destructor of vector? like this

Technically yes but what if you want a vector of pointers that does not represent ownership? You could easily end up either double-deleting an object, or trying to delete a stack-based object:

obj obj_a;
obj* obj_b = new obj;

vector<obj*> obj_ptrs;
obj_ptrs.elem[0] = &obj_a;
obj_ptrs.elem[1] = &obj_a;
obj_ptrs.elem[2] = obj_b;

delete obj_b;

Whether the pointed objects need to be deleted with the vector is none of the vector's business.

The cleanest way to address that is to use std::unique_ptr, which is an object type that holds a pointer and deletes it when it gets destroyed:

#include <memory>

template <typename T> struct vector {
// ...
~vector() {
// The vector is only responsible for deleting the array.
delete[] elem;
}
};
// ...

void foo() {
vector<std::unique_ptr<obj>> obj_ptrs;

obj_ptrs.elem[0] = std::make_unique<obj>();
obj_ptrs.elem[1] = std::make_unique<obj>();
obj_ptrs.elem[2] = std::make_unique<obj>();

obj stack_obj;

vector<obj*> obj_no_own_ptrs;
obj_no_own_ptrs.elem[0] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[1] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[2] = &stack_obj;

// Everything gets deleted
// No double-delete concern
}

Where to properly delete dynamically allocated object in loop in C++

Assuming that foo.getNewT() is handing ownership of the memory over to the caller:

T * t;
t = foo.getNewT();
//while (!t->isFinalT()) // if foo.getNewT ever returns NULL, this will be UB!!!
while (t != nullptr && !t->isFinalT())
{
// ...
delete t; // if you now own it and are no longer going to use it, yes, delete it here
t = foo.getNewT();
}
delete t; // you also need this one to delete the "final" t

However, you can avoid having to do it yourself by using std::unique_ptr:

std::unique_ptr<T> t;
t.reset(foo.getNewT());
while (t && !t->isFinalT())
{
// ...
t.reset(foo.getNewT());
}

Alternatively, you could rewrite the loop to flow a bit better:

std::unique_ptr<T> t;
do
{
t.reset(foo.getNewT());
if (t)
{
// do stuff with t
}
} while (t && !t->isFinalT());

the code ran fine without the delete statement and crashed when I
added the delete statement.

Are you sure getNewT is handing ownership of the T* to you? If you delete it, and then it tries to delete it later, you will end up with a heap corruption. If it is handing ownership over to the caller, and you do not delete it, you get a memory leak.

With the additional information in your edit:

char * strVar = new char[11];

That line is unnecessary if you declare strVar as either a std::string or a char[11]. If you attempt to copy any of those T objects, you'll be using the default copy constructor (as you have not defined one), which will do a shallow copy (that is, copy the value of the pointer for strVar). When you delete 2 Ts that are both pointing to the same memory location, you get a heap corruption. The most robust solution would be to declare strVar as a std::string.



Related Topics



Leave a reply



Submit