I'm implementing a binary heap class. The heap is implemented as an array that is dynamically allocated. The heap class has members capacity, size and a pointer to an array, as:
class Heap
{
private:
Heap* H;
int capacity; //Size of the array.
int size; //Number of elements currently in the array
ElementType* Elements; //Pointer to the array of size (capacity+1)
//I've omitted the rest of the class.
};
My construcor looks like this:
Heap::Heap (int maxElements)
{
H = ( Heap* ) malloc ( sizeof ( Heap ) );
H -> Elements = ( ElementType* ) malloc ( ( maxElements+1 )*sizeof ( ElementType ) );
H -> Elements[0] = DUMMY_VALUE; //Dummy value
H -> capacity = maxElements;
H -> size = 0;
}
Since I'm mallocing twice and dereferencing both pointers in the constructor, I should check whether it succeeds. But what should I do if it fails? The constructor can't itself return anything to indicate that it failed. Is it good programming practice to avoid mallocs in constructors altogether?
Unlike new and delete operators malloc does not call the constructor when an object is created.
The malloc() function is used for the declaration of the dynamic memory. An array of a struct can be declared either using the static memory or dynamic memory, in this write-up, we will discuss the array of structs using the malloc() function.
A malloc() in C++ is a function that allocates memory at the runtime, hence, malloc() is a dynamic memory allocation technique. It returns a null pointer if fails. Syntax: pointer_name = (cast-type*) malloc(size); Here, size is an unsigned integral value (cast to size_t) which represents the memory block in bytes.
First of all, you do not need a Heap*
member variable inside your Heap
object, and you certainly should not be allocating memory for it in the Heap
constructor - that's just asking for trouble. Nor should you be accessing your member variables as H->Elements
, but rather simply as Elements
.
The only thing you need to allocate is the Elements
array.
With regards to handling allocation failures, constructors should indicate failures via an exception. There is even a standard exception type, std::bad_alloc
that is usually used to indicate a failure to allocate memory.
For example:
#include <stdexcept> // for std::bad_alloc
...
Heap::Heap (int maxElements)
{
Elements = ( ElementType* ) malloc ( ( maxElements+1 )*sizeof ( ElementType ) );
if (Elements == NULL)
throw std::bad_alloc("Failed to allocate memory");
...
}
Even better, use new
rather than malloc
to allocate the memory. new
will automatically throw an exception of type std::bad_alloc
if it fails to allocate memory.
Example:
Heap::Heap (int maxElements)
{
Elements = new ElementType[maxElements + 1]; // throws std::bad_alloc on failure
...
}
Note: if you use new
to allocate the object, you must use delete
to free it rather than free
. (Correction: In the example above, you are using the array form of new, new[]
, so you should call the array form of delete, delete[]
).
Finally, you haven't shown how ElementType
is declared, but if it's a type that has a non-default constructor/destructor (or if it's a template parameter which means it can potentially be such a type), you have to use new
rather than malloc
when allocating it because malloc
will not call the constructor (and free
will not call the destructor). In general, it's good practice to just always use new
and delete
in C++ rather than malloc
and free
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With