2010-09-01 8 views
0

Ceci est ma première tentative pathétique en C++. J'ai fait une pile basée sur un tableau en C++ et le destructeur jette un peu de mémoire. Je ne peux pas comprendre ce qui s'est mal passé.Pile basée sur un tableau - erreur dans le destructeur



#include <stdio.h> 
#include <iostream> 
#include <exception> 

using namespace std; 

class FullStackException : public exception { 
    virtual const char* what() const throw() { 
     return "Stack is full."; 
    } 
} fsex; 

class EmptyStackException : public exception { 
    virtual const char* what() const throw() { 
     return "Stack is empty."; 
    } 
} esex; 

template <class D> 
class ArrayBasedStack { 
private: 
    int t; //t represents top 
    D *S; 
    int arrSize; 
public: 
    ArrayBasedStack(int arraySize = 10); 
    ~ArrayBasedStack(); 
    int size(); /*returns the number of elements stored*/ 
    void push(D&); /*inserts an element*/ 
    D pop(); /*removes and returns the last inserted element*/ 
    D top(); /*returns the last inserted element without removing it*/ 
    int isEmpty(); /*indicates whether no elements are stored*/ 
}; 

template <class D> 
ArrayBasedStack<D>::ArrayBasedStack(int arraySize) { 
    /* Elements are added from left to right */ 
    S = new D[arraySize]; 
    arrSize = arraySize; 
    /* t keeps track of the index of the top element */ 
    t = -1; 
} 

template <class D> 
ArrayBasedStack<D>::~ArrayBasedStack() { 
    if(S != NULL) { 
     int i = 0; 
     for(i = 0; i < size(); i++) { 
      S[i] = NULL; 
     } 
     cout << "about to delete S" << endl; 
     delete[] S; 
    } 
} 

template <class D> 
int ArrayBasedStack<D>::size() { 
    return t; 
} 

template <class D> 
void ArrayBasedStack<D>::push(D& data) { 
    if(t == arrSize) { 
     throw fsex; 
    } else { 
     S[t] = data; 
     t++; 
    } 
} 

template <class D> 
D ArrayBasedStack<D>::pop() { 
    if(isEmpty()) { 
     throw esex; 
    } 
    D element = S[t]; 
    S[t--] = NULL; 
    return element; 
} 

/* 
* returns true if the stack is empty, false otherwise 
*/ 
template <class D> 
int ArrayBasedStack<D>::isEmpty() { 
    return (t < 0); 
} 

int main(int argc, char *argv[]) { 

    char inputs[][10] = { 
     "str1" 
    }; 

    char *i = NULL; 

    ArrayBasedStack<char *> stack; 
    i = inputs[0]; 
    stack.push(i); 
    try { 
     stack.pop(); 
    } 
    catch(exception& ex) { 
     cout << "ERR:" << ex.what() << endl; 
    } 
    return 0; 
} 

 
+0

Je ne sais pas comment cela est pathétique. C'est beaucoup mieux que je n'ai jamais fait quand j'ai appris le C++. :) – Mike

+1

Bien joué. BTW - vous utilisez S [i] = NULL dans votre destructeur et pop(), mais cela ne fait rien de particulièrement utile (pour D = char *, cela signifie que l'impression de la pile entière peut permettre une double vérification t, à condition de ne pas appuyer sur (NULL)), mais cela veut dire que tout type D avec lequel vous instanciez doit être assignable à partir de NULL, ce qui est une limitation assez importante et inutile. En C++, x = NULL n'est pas nécessaire comme indication à un garbage collector. Vous appelez également en toute sécurité pour supprimer NULL, de sorte que le destructeur peut simplement supprimer [] S, mais il est normal que vous ayez été prudent à ce sujet. –

Répondre

2

La ligne de problème est

t = -1; 

devrait être

t = 0; 

parce que lorsque vous ajoutez premier élément, le code suivant est étét exécutée

} else { 
     S[t] = data; // t == -1 
     t++; 
    } 
+0

+1, bat moi. La meilleure pratique consiste à toujours éviter d'avoir des index invalides. – Potatoswatter

+0

Le code nécessite plus de modifications qu'une seule affectation. Certaines parties sont basées sur l'hypothèse que t est un passé le haut et certains dans l'hypothèse que c'est le sommet. –

0

Voici la coupable.

template <class D> 
void ArrayBasedStack<D>::push(D& data) { 
    if(t == arrSize) { 
     throw fsex; 
    } else { 
     S[t] = data;  // Should be S[++t] = data; 
     t++;    // Comment out this line 
    } 
} 

Cette implemntation suppose que « t » pointe vers l'élément le plus haut sur la pile, plutôt que vers l'emplacement suivant disponible pour push

Notez que l'opérateur [] et l'opérateur ++ ont la même priorité. Comme ils s'associent de gauche à droite, [] est évalué avant l'opérateur ++.

Dans votre implémentation, voici le problème. Avec t étant initialisé à -1, vous écrasez au-delà de l'indice de tableau qui est à S [-1], ce qui conduit à undefined behavior.

Au moins sur mon système, le problème disparaît en essayant de libérer de la mémoire dans le destructeur de la classe de pile. Ceci est un exemple classique d'une syptom étant visible bien après la gaffe Sprinkles est

suggéreraient aussi push de prendre les paramètres comme D const &

Questions connexes