Frage

Ich weiß C, aber ich bin nicht gut in C ++.

Der folgende Code stürzt ab (in getVal (), indem Referenz als Parameter in Ordnung ist). Und Wert von *p wird nach dem ersten geändert cout Aussage. Es sieht so aus, dass es ein Überschreiben gibt, der aus dem Gedächtnis verursacht wird.

Meine Frage ist, warum es abgestürzt ist (oder warum sein Wert geändert wird). Es ist 'Call by Value' of Objekt, also sollte es trotzdem funktionieren?

class myclass { 
  int *p; 

  public: 
    myclass(int i); 
    ~myclass() { delete p; } 
    int getval(myclass o); 
}; 

myclass::myclass(int i) 
{ 
  p = new int; 

  if (!p) { 
    cout << "Allocation error\n"; 
    exit(1); 
  } 

  *p = i; 
}

int myclass::getval(myclass o) 
{ 
  return *o.p; 
} 

int main() 
{ 
  myclass a(1), b(2); 

  cout << a.getval(a) << " " << a.getval(b) << endl; 
  cout << b.getval(a) << " " << b.getval(b) << endl; 

  return 0; 
} 
War es hilfreich?

Lösung

Meine Frage ist, warum es abgestürzt ist (oder warum sein Wert geändert wird).

Dies ist ein sehr häufiges Problem von flache Kopie und doppelt löschen. Der Compiler nimmt den Standardkopiekonstruktor und beides auf a.p und o.p zeigen auf denselben Speicherort. Wenn beide Objekte ihren Destruktor berufen, die delete p; Aussage wird ausgeführt zweimal. Das mehrmals gleiche Speicher zu befreien ist ein undefiniertes Verhalten Und es führt zu Absturz in Ihrem System.

Es ist 'Call by Value' of Objekt, also sollte es trotzdem funktionieren?

Wenn ordnungsgemäß codiert, dann Jawohl es würde funktionieren. Eine tiefe Kopie von machen p'S Inhalt und dann sollte es funktionieren. Es ist jedoch besser, nach Referenz zu bestehen, bis es möglich ist.

Andere Tipps

Lesen Sie auf die Regel von drei.

Im Wesentlichen unterstützt Ihr Code nicht das Kopieren nach Wert.

Der dynamisch zugewiesene Speicher wird also vorzeitig (vom Destruktor) ausgetrieben.

Prost & hth.,

Was Sie tun, ist in Bezug auf die Sprache C ++ erlaubt. Aber das ist wirklich sehr schlecht programmiert. Es möchte nicht zu jeder Zeile Ihres Codes kommentieren. Stattdessen schreibe ich den gesamten Code neu, und Sie vergleichen diesen Code mit Ihrem und sehen auch die Kommentare, die in den Code eingebettet sind:

class myclass { 
  int p;  //no pointer, as it is not needed

  public: 
    myclass(int i) : p(i) {} //use member initialization-list 
    int getval() const  //no parameter, and make the function const
    {
         return p;
    }
}; 

int main() 
{ 
  myclass a(1), b(2); 

  cout << a.getval() << endl;
  cout << b.getval() << endl; 
  return 0; 
} 

Sie bestehen Myclass als Wert, also wird Kopie erstellt. Wenn Myclass :: GetVal zurückgibt, wird der Stapel abgerollt und Myclass Destructor wird aufgerufen und gibt den Speicher frei, auf den Zeiger im anderen Objekt verweist.

Sie löschen P hier doppelt, ein gemeinsamer Zeiger kann nützlich sein, wenn Sie keine tiefe Kopie durchführen möchten. Solange es möglich ist und Sinn macht, versuchen Sie stattdessen, automatische Variablen zu verwenden (int anstelle von int*)

Sie haben den Kopierkonstruktor nicht implementiert (wenn Sie dies tun, denken Sie an die Regel von drei). Wenn Kopien zerstört werden, befreien Sie dieselbe Speicher mehrmals.

Hinweise:

Implementieren Sie den Kopierkonstruktor:

myclass(const myclass& other)
{
   p = new int;
   *p = *other.p;
}

Pass durch Referenz:

int getval(const myclass& o); 

Eine gute Regel wäre auch, Funktionen zu erstellen, die nicht vom Objekt selbst statisch abhängen (dies wird Ihnen in diesem speziellen Fall nicht helfen, aber dennoch nützlich). Seit getval Zugriff auf keine Objektmitglieder, Sie können es statisch machen.

Gründe für den Absturz:

Wenn du anrufst getval(o), eine Kopie von o wird erstellt und sein Mitglied zeigt auf denselben Ort wie das ursprüngliche Objekt, da Sie keinen Kopierkonstruktor deklariert haben. Die Kopie wird zerstört und der Speicher gelöscht. Das ursprüngliche Objekt bleibt beschädigt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top