1

Ich habe ein Problem mit der dynamischen Speicherzuweisung.C++: Dynamischen Speicher freigeben, wenn das abgeleitete Klassenobjekt zerstört wird

Unten sehen Sie eine abgeleitete Klasse, die einen Zeiger für eine Namensvariable enthält, die dynamisch mit der Methode void name(const char* name) zugewiesen wird. Die Funktion wird vom Produktkonstruktor ausgeführt, der beim Erstellen des Objekts einen Namen für die Produktklasse festlegt. Hier ist die Klasse:

namespace sict { 
    class Product :public Streamable { 

    char* name_; 

public: 

    Product(const char* name); 
    virtual ~Product(); 

    void name(const char* name); 

} 

Und hier ist der Name Funktion selbst, zusammen mit dem ein Argument Konstruktor:

void sict::Product::name(const char * name) { 
    int g = strlen(name); 
    name_ = new char[g]; 
    strncpy(name_, name, g); 
    name_[g] = 0; 
} 

Product::~Product() { 
    delete [] name_; 
    name_ = nullptr; 
} 

Für mich dieser Code das Objekt fähig genug geschaffen scheint es dann ruhig zu zerstören, wenn es austritt der Umfang der Funktion, in der es ausgeführt wird. Wenn die Funktion jedoch endet und der Destruktor ausgeführt wird, stürzt das Programm bei delete [] name_ ab. Das Ausführen des Programms auf Visual Studio-Compiler scheint keine bestimmten Fehler (außer dem Einfrieren des Programms) zu ergeben, aber der GCC-Compiler erkennt eine Art Heap-Beschädigung. Würde jemand wissen, warum das passiert?

+6

'name_ [g] = 0;' schreibt über das Ende des zugeordneten Array, den Heap korrumpieren. Versuchen Sie, 'g' zu' strlen (name) + 1' zu ändern, um zu bestätigen. Da dies C++ ist, wäre es viel besser, wenn Sie ['std :: string'] (http://en.cppreference.com/w/cpp/string/basic_string) verwenden und die Speicherverwaltung für Sie übernehmen würde. –

+3

Sie halten sich nicht an die [Regel von 3] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). – PaulMcKenzie

+4

Oh, das ist einfach, benutze einfach 'std :: string'. Du weißt, es ist C++. Not C. –

Antwort

3

Ich bin mir nicht sicher, warum Sean Cline seinen Kommentar nicht als Antwort postet, aber Sean hat Recht.

name_ wird g Elemente gegeben und dann name_[g] wird auf Null gesetzt, aber name_[g] ist eine nach dem Ende des Arrays. Verwenden Sie entweder name_ = new char[g+1]; oder name_[g-1] = 0;, damit Sie nicht über das Ende des Arrays hinausgehen.

Auch, wie einige Kommentare weisen darauf hin, jedes Mal, wenn eine Klasse, die Speicher dynamisch zuweist, stellen Sie sicher, dass Sie definieren den Copykonstruktor, die Zuweisungsoperator und die destructor. Wenn Sie einen vermissen, führt die Standardimplementierung eine seichte Kopie aus, die Kopfschmerzen für Sie verursachen kann.

Eine flache Kopie ist, wenn der Zeiger anstelle der Daten kopiert wird, auf die er zeigt. Wenn in Ihrem Fall ein Objekt dieser Klasse jemals kopiert oder zugewiesen wird, erhalten Sie zwei Objekte, die auf die gleichen Daten im Heap verweisen, und sie würden beide versuchen, sie zu löschen, wenn sie ihre Destruktoren ausführen.

Für weitere Informationen über diese Funktionen siehe die Rule of Three