2011-06-10 3 views
5

J'implémente une classe de tas binaire. Le tas est implémenté en tant que tableau alloué dynamiquement. La classe de tas a une capacité de membres, la taille et un pointeur sur un tableau, comme:Malloc dans les constructeurs

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

Mon construcor ressemble à ceci:

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

Depuis que je suis allouer de deux fois et déréférencement les deux pointeurs dans le constructeur , Je devrais vérifier si ça réussit. Mais que dois-je faire si cela échoue? Le constructeur ne peut rien retourner pour indiquer qu'il a échoué. Est-ce une bonne pratique de programmation d'éviter complètement les mallocs dans les constructeurs?

+2

Bonjour, @Sahil! Bienvenue dans Stack Overflow. Merci d'avoir collé le code correspondant à votre question, mais veuillez le formater en code lorsque vous poserez votre question suivante (indiquez chaque ligne quatre espaces ou utilisez le bouton '{}'). De plus, je ne pense pas que vous ayez besoin de votre variable membre "H". L'espace pour l'objet 'Heap' a déjà été alloué au moment où votre constructeur est entré. Vous avez juste besoin d'allouer de l'espace pour le tableau 'Elements'. –

+0

Je ne comprends pas pourquoi votre objet Heap a un pointeur vers un autre objet Heap, en particulier lorsque vous n'utilisez pas les membres de l'objet que vous construisez. Je perdrais le premier 'malloc' et utiliserais directement les membres de votre objet. –

+0

En fait, il est assez mauvais d'avoir le pointeur H sur la mémoire où le constructeur ne s'est pas exécuté. Je peux parier que déréférencer 'H' invoque un comportement indéfini. Pourquoi ne pas simplement stocker 'capacity',' size' et 'Elements' directement dans votre classe? – Vlad

Répondre

14

Tout d'abord, vous ne pas besoin d'une variable membre Heap* l'intérieur de votre objet Heap, et vous ne devriez certainement pas allouer de la mémoire pour le constructeur dans Heap - qui est juste d'avoir des ennuis. Vous ne devriez pas non plus accéder à vos variables membres comme H->Elements, mais simplement comme Elements.

La seule chose que vous devez allouer est la baie Elements. En ce qui concerne la gestion des échecs d'allocation, les constructeurs doivent indiquer les échecs via une exception. Il existe même un type d'exception standard, std::bad_alloc, généralement utilisé pour indiquer l'échec de l'allocation de la mémoire.

Par exemple:

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

Mieux encore, utiliser new plutôt que malloc d'allouer la mémoire. new lèvera automatiquement une exception de type std::bad_alloc s'il ne parvient pas à allouer de la mémoire.

Exemple:

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

Remarque: si vous utilisez new d'affecter l'objet, vous devez utiliser delete pour le libérer plutôt que free. (Correction: Dans l'exemple ci-dessus, vous utilisez la forme de tableau de nouveau, new[], vous devez donc appeler la forme de tableau de suppression, delete[]).

Enfin, vous n'avez pas montré comment ElementType est déclarée, mais si elle est un type qui a un constructeur non-default/destructor (ou si elle est un paramètre de modèle qui signifie qu'il peut potentiellement être un tel type), vous avoir pour utiliser new plutôt que malloc lors de l'allocation car malloc n'appelera pas le constructeur (et free n'appellera pas le destructeur). En général, il est bon de toujours utiliser new et delete en C++ plutôt que malloc et free.

+0

@Roddy Mais ce n'est pas 'new Heap', c'est' Heap * H = (Heap *) malloc (taille de (Heap)) '- le constructeur ne sera pas appelé ;-) –

+1

Si vous utilisez' new [] ', n'utilisez pas' delete' - utilisez 'delete []'! –

+0

@Khaled: Roddy commentait ma réponse qui recommandait à l'origine de remplacer 'H = (Heap *) malloc (sizeof (Heap))' par 'H = new Heap'. C'est avant que je me rende compte à quel point c'était ... – HighCommander4

1

Vous allouez l'objet dans son propre constructeur? N'a pas de sens:

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

constructeur est appelé par l'opérateur new, juste après l'allocation de mémoire.Si vous essayez de créer un singleton - utiliser une méthode statique qui instancier l'objet, et appeler

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 
} 

à votre question: malloc est une fonction C. En C++ - utilisez new. Vous n'avez pas besoin de vérifier les valeurs de retour, puis new lèvera une exception en cas d'échec.

+1

Oui, ce bit n'a pas de sens. Mais ce n'est pas une réponse à sa question, simplement une observation utile de votre part. Peut-être que cela devrait être un commentaire au lieu de répondre? –

5

Vous devriez apprendre quelques 'règles de la route' C++ de base, dont le premier est:

Utilisez le Standard Template Library!

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

Et votre constructeur? Vous n'en avez pas besoin.

En général, toute utilisation de malloc() ou free() en C++ est une «odeur de code». C'est un moyen infaillible de se retrouver avec des objets mal construits, des débordements de mémoire tampon et des fuites de mémoire. Utilisez new et delete, de préférence avec des pointeurs intelligents.

Ou, mieux encore. faites simplement construire vos objets de manière statique chaque fois que c'est possible.