2011-06-10 18 views
5

Estoy implementando una clase de montón binario. El montón se implementa como una matriz que se asigna dinámicamente. La clase tiene miembros montón de capacidad, tamaño y un puntero a una matriz, como:Malloc en constructores

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. 
}; 

Mi construcor se ve así:

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; 
} 

Desde que estoy mallocing dos veces y eliminación de referencias ambos punteros en el constructor , Debería verificar si tiene éxito. Pero, ¿qué debo hacer si falla? El constructor no puede devolver nada para indicar que falló. ¿Es una buena práctica de programación evitar mallocs en constructores en conjunto?

+2

Hola, @Sahil! Bienvenido a Stack Overflow. Gracias por pegar el código que es relevante para su pregunta, pero por favor formatéelo como código cuando haga su próxima pregunta (sangría cada línea de cuatro espacios, o use el botón etiquetado '{}'). Además, no creo que necesite su variable de miembro 'H' en absoluto. El espacio para el objeto 'Heap' ya ha sido asignado antes de que se ingrese su constructor. Solo necesita asignar espacio para la matriz 'Elementos'. –

+0

No entiendo por qué su objeto Heap tiene un puntero a otro objeto Heap dentro, especialmente cuando no usa los miembros del objeto que está construyendo. Perdería el primer 'malloc' y usaría los miembros de tu objeto directamente. –

+0

En realidad, es una mala práctica tener el puntero 'H' apuntando a la memoria donde el constructor no se ejecutó. Puedo apostar a que desreferenciar 'H' invoca un comportamiento indefinido. ¿Por qué no simplemente almacenar 'capacity',' size' y 'Elements' directamente en su clase? – Vlad

Respuesta

14

En primer lugar, ¿verdad no necesita una variable Heap* miembro dentro de su objeto Heap, y que sin duda no se debe asignar memoria para él en el Heap constructor - eso es sólo buscar problemas. Tampoco debe acceder a sus variables miembro como H->Elements, sino simplemente como Elements.

Lo único que necesita asignar es la matriz Elements.

Con respecto al manejo de fallas de asignación, los constructores deben indicar fallas a través de una excepción. Incluso hay un tipo de excepción estándar, std::bad_alloc que generalmente se utiliza para indicar una falla en la asignación de memoria.

Por ejemplo:

#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"); 
    ... 
} 

Mejor aún, utilice new en lugar de malloc para asignar la memoria. new lanzará automáticamente una excepción de tipo std::bad_alloc si no puede asignar memoria.

Ejemplo:

Heap::Heap (int maxElements) 
{ 
    Elements = new ElementType[maxElements + 1]; // throws std::bad_alloc on failure 
    ... 
} 

Nota: si utiliza new para asignar el objeto, debe utilizar delete para liberarla en lugar de free. (Corrección: en el ejemplo anterior, está utilizando la forma de matriz de new, new[], por lo que debe llamar a la matriz de delete, delete[]).

Por último, no se ha demostrado cómo ElementType se declara, pero si se trata de un tipo que tiene un constructor no predeterminado/destructor (o si se trata de un parámetro de plantilla que significa que potencialmente puede ser un tipo tal), que tiene para usar new en lugar de malloc al asignarlo porque malloc no llamará al constructor (y free no llamará al destructor). En general, es una buena práctica usar siempre new y delete en C++ en lugar de malloc y free.

+0

@Roddy Pero no es 'nuevo Heap', es' Heap * H = (Heap *) malloc (sizeof (Heap)) '- el constructor no se llamará ;-) –

+1

Si usa' new [] ', no use' delete' - use 'delete []'! –

+0

@Khaled: Roddy estaba comentando mi respuesta, que originalmente recomendaba reemplazar 'H = (Heap *) malloc (sizeof (Heap))' con 'H = new Heap'. Eso es antes de darme cuenta de lo equivocado que estaba ... – HighCommander4

1

¿Está asignando el objeto en su propio constructor? No tiene sentido:

H = (Heap*) malloc (sizeof (Heap)); 

constructor es llamado por el operador new, justo después de la asignación de memoria.Si usted está tratando de crear un producto único - utilizar un método estático que será una instancia del objeto, y llamar a

class Heap{ 
public: 
    static Heap* Get(); 
private: 
    Heap(); 
    static Heap* H; 
} 

Heap *Heap::H = 0; 

Heap * Heap::Get() 
{ 
    if (!H) 
     H = new (Heap); 
    return H; 
} 

Heap::Heap() 
{ 
    // whatever else 
} 

A su pregunta: malloc es una función C. En C++: use new. No necesita verificar los valores de retorno, entonces, new lanzará una excepción en caso de falla.

+1

Sí, ese bit no tiene sentido. Pero esa no es una respuesta a su pregunta, simplemente una observación útil de su parte. ¿Tal vez esto debería ser un comentario en lugar de una respuesta? –

5

usted debe aprender algunas 'reglas del camino' básicos C++, el primero de los cuales es:

utilizar la biblioteca de plantillas estándar!

class Heap { 
    private: 
    std::vector<ElementType> elements; 
} 

¿Y su constructor? No necesitas uno.

En general, cualquier uso de malloc() o free() en C++ es un "olor a código". Es una manera segura de terminar con objetos construidos incorrectamente, desbordamientos de búfer y fugas de memoria. Use new y delete, preferiblemente con punteros inteligentes.

O, mejor aún. solo tiene sus objetos construidos estáticamente siempre que sea posible.