Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Malloc in constructors

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?

like image 240
Sahil Sapre Avatar asked Jun 10 '11 19:06

Sahil Sapre


People also ask

Does malloc call constructor C++?

Unlike new and delete operators malloc does not call the constructor when an object is created.

Can you malloc a struct?

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.

What is malloc () in C++?

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.


1 Answers

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.

like image 50
HighCommander4 Avatar answered Oct 26 '22 18:10

HighCommander4