2012-04-04 11 views
2

Also bin ich neugierig auf den Grund, warum der folgende Code abstürzt. Ich schätze die Hilfe.können Sie mir sagen, warum stürzt dieser Code ab?

#include <iostream> 
using namespace std; 

class temp 
{  
    public: 

    temp(int i) 
    { 
     intPtr = new int(i); 
    } 

    ~temp() 
    { 
     delete intPtr; 
    } 

    private: 
    int* intPtr; 
}; 

void f (temp fInput) 
{ 
    cout << "f called" << endl; 
} 

int main() 
{ 
    temp x = 2; 
    f(x); 
    return 0; 
} 
+1

Können Sie "Absturz" definieren? – josephthomas

+0

@ Ed S: Ich stimme allerdings zu, dass manchmal, was wir für einen Absturz halten, anders sein könnte als das, was er für einen Absturz hält. – josephthomas

+0

@josephthomas: Ja, das habe ich mir gedacht, weshalb ich meinen Kommentar kurz nach dem Posten gelöscht habe :) Wir können uns auf die korrekte Verwendung des Begriffes einigen ... Ob die meisten Anfänger ihn richtig benutzen werden, ist ein anderes Problem –

Antwort

5

Der Zeiger kopiert wird, wenn x (impliziten Copykonstruktor) übergeben wird und der Destruktor bezeichnet wird zweimal (bevor die Funktion zurückkehrt und vor dem Haupt Returns), so wird der Speicher zweimal gelöscht.

Verwenden std::shared_ptr<int> hier stattdessen anstelle eines rohen int Zeiger (vorausgesetzt, Sie wollen das gleiche Verhalten sein, das heißt die gleiche int von beiden temp s verweisen, andernfalls den Kopierkonstruktor implementieren, bewegen Konstruktor und Zuweisungsoperator selbst).

#include <memory> 

class temp {  
public: 
    temp(int i) : intPtr(std::make_shared<int>(i)) { 

    } 

private: 
    std::shared_ptr<int> intPtr; // reference counting ftw 
}; 
+0

Oder führen Sie die Klasse nur korrekt aus, um damit zu beginnen (z. B. korrekte Kopiesemantik usw.). –

+0

Das ist auch möglich, abhängig vom gewünschten Verhalten. –

+0

.... korrektes Verhalten ist immer wünschenswert. –

5

Der Absturz tritt auf, weil Sie x passieren.

Nach dem Umfang der f Funktion wird x 's Destruktur aufgerufen und intPtr gelöscht.

Das wird jedoch Speicher löschen, der immer noch in Bereich für main ist. Daher wird nach dem Aufruf von return 0 versucht, Speicher zu löschen, der bereits vorhanden ist, während Sie zweimal auf demselben Zeiger löschen.

diesen Fehler zu beheben, ändern

void f (temp fInput) 

zu

void f (const temp& fInput) 

Alternativ Sie in mit einem std::shared_ptr aussehen könnte.

+0

Das Hinzufügen eines Kopierkonstruktors und eines Zuweisungsoperators wäre ebenfalls eine gute Idee. Sie könnten auch std :: shared_ptr anstelle eines rohen Pointers verwenden, da es sich um die Semantik von Kopien kümmert. –

+0

Ich stimme zu, ich wollte dem Plakat eine Lösung geben, die ihm mit minimalem Aufwand helfen könnte. Es gibt viele Möglichkeiten, wie dieser Crash gelöst werden kann. – josephthomas

5

Sie verletzen The Rule of Three

Sie pflegen einen Zeiger Mitglied und Sie übergeben eine Kopie des Objekts an die Funktion f. Also, das Endergebnis ist, dass Sie delete zweimal auf dem gleichen Zeiger aufrufen.

1

Das Problem, das Sie hier treffen, ist ein doppeltes Löschen. Da Sie hier keine Kopierkonstruktoren definiert haben, macht C++ das gerne für Sie. Die Implementierung führt dies durch Ausführen einer flachen Kopie aller Inhalte durch.

f(x); 

Diese Linie funktioniert, indem eine Kopie x erstellen und zu f vorbei. An diesem Punkt gibt es 2 temp Instanzen, die ein einzelnes Mitglied besitzen. Beide Instanzen werden diesen Zeiger löschen, und das ist wahrscheinlich, was Ihren Absturz verursacht.

um dieses Problem zu umgehen Sie eine Reihe von Maßnahmen ergreifen können,

  1. einen Zeigertyp für den Austausch wie shared_ptr<T>
  2. , die durch ref übergeben werden zwingt die Instanz erstellen unkündbare Copykonstruktor gemeint Verwenden

Ein Beispiel # 2 ist

class temp { 
    temp(const temp& other); 
    temp& operator=(const temp& other); 
public: 
    // Same 
}; 

Jetzt wird die Zeile f(x) einfach nicht kompiliert, da sie nicht auf den notwendigen Kopierkonstruktor zugreifen kann. Es zwingt es stattdessen, f neu zu definieren, um eine Kopie zu verhindern.

void f(const temp& fInput) { 
    ... 
} 
Verwandte Themen