1

Ich versuchte, ein Universitätsproblem zu lösen, indem ich die gegebenen Anweisungen befolgte. Der Code kompiliert, aber es erzeugt eine Warnung über Speicher. Hier ist der Kern des Codes:C++ shared_ptr Vererbungsspeicherprobleme "Bad deallocation"

#include <iostream> 
#include <vector> 
#include <memory>  
using std::vector; 
using std::shared_ptr; 
using std::make_shared; 

class ApsClass { 
    protected : 
     double goose; 

    public : 
     virtual ~ApsClass() {} 
     virtual shared_ptr<ApsClass> clone() const = 0; 
     double GetGoose() const { return goose; } 
}; 


class DerivedClass : public ApsClass { 
    public : 
     ~DerivedClass() {} // Warning here* 
     DerivedClass(double goose) { DerivedClass::goose = goose; } 
     shared_ptr<ApsClass> clone() const override; 
}; 

shared_ptr<ApsClass> DerivedClass::clone() const { 
    return make_shared<DerivedClass>(goose); 
} 

class Storage { 
    vector<shared_ptr<ApsClass>> geese; 

    public : 
     Storage() {} 
     ApsClass *AddApsClass(ApsClass *pok); 
     void DelApsClass(ApsClass *pok); 
}; 

ApsClass *Storage::AddApsClass(ApsClass *pok) 
{ 
    // The instructions stated that the object pointed at by pok has no 
    // other pointers pointing at it, and should now be "owned" by geese 
    geese.push_back(shared_ptr<ApsClass>(pok)); 
    return pok; 
} 

void Storage::DelApsClass(ApsClass *pok) 
{ 
    for (int i = 0; i < geese.size(); i++) 
     if (geese[i] == shared_ptr<ApsClass>(pok)) { 
      geese.erase(geese.begin() + i); 
      break; 
     } 
} 

int main() 
{ 
    Storage Foo; 
    ApsClass *s = Foo.AddApsClass(new DerivedClass(0.5)); 
    Foo.DelApsClass(s); 
    return 0; 
} 

main() ist im Grunde der Code von einem Autotest, ich soll den Rest des Programms ändern, um main() zu machen richtig.
Die Warnung wird in der Destruktordefinition der abgeleiteten Klasse * gemeldet, bei der Übersetzung ins Englische wird lediglich "Unzulässige Zuordnung" angezeigt. Meine Frage ist: Wo und warum tritt dieses Problem im Code auf?

Der Code schneide ich habe aus hat keinen Einfluss auf die Speicherzuweisung (hoffe ich), und wird über autotesting getestet, die ich habe nicht viel Zugang zu. Ein Test Bericht folgend unter dem anderen:

Invalid read of size 8 ... 
Address 0x51f0090 is 0 bytes inside a block of size 56 free'd 

und

==10216== Jump to the invalid address stated on the next line 
==10216== at 0x0: ??? 
Address 0x0 is not stack'd, malloc'd or (recently) free'd 

und

==10216== Process terminating with default action of signal 11 (SIGSEGV) 
==10216== Bad permissions for mapped region at address 0x0 
==10216== at 0x0: ??? 

Wenn weitere Details benötigt werden, kann ich hier einige des ursprünglichen Code setzen.

Antwort

6

Jedes Mal, wenn Sie shared_ptr<ApsClass>(pok) tun, erstellen Sie eine neue shared_ptr, die nicht über alle anderen shared_ptr s auf das gleiche Objekt verweist. Wenn dieses shared_ptr zerstört wird, zerstört es das Objekt.

Aber weil du es mehrmals zu tun (zweimal, in Ihrem Fall) das Objekt wird mehr als einmal zerstört.

Nur shared_ptr s von normalen Zeiger haben dieses Problem geschaffen. Erstellen Sie eine shared_ptr von einem anderen shared_ptr ist in Ordnung.

Sie sollten ein shared_ptreinmal schaffen - diese diese

ApsClass *s = Foo.AddApsClass(new DerivedClass(0.5)); 
Foo.DelApsClass(s); 

zu

ändern:

shared_ptr<ApsClass> aps(new DerivedClass(0.5)); 
shared_ptr<ApsClass> s = Foo.AddApsClass(aps); 
Foo.DelApsClass(s); 

und ändern ApsClass *-shared_ptr<ApsClass>überall sonst.

+3

Ich zweite, dass. Sobald ein roher Pointer durch 'shared_ptr' verwaltet wird, sollte der rohe Pointer nicht mehr verwendet werden (außer zur Verbindung mit Legacy-Code, aber in diesem Fall würden Sie' shared_ptr :: get() 'verwenden). Übergeben Sie stattdessen nur das 'shared_ptr' (oder in Fällen, in denen Sie zirkuläre Verweise verhindern müssen, ein' weak_ptr'), um solche Probleme zu vermeiden. – zett42

+0

Ich verstehe. Allerdings ist das Problem jetzt (ich werde dies zur Frage ETA), dass der Code in main() (modifizierter) Code vom Autotest ist. Ich darf die main() hier nicht ändern. – sishke

+1

@sishke Dann zumindest aber ändern 'Gänse [i] == Shared_ptr (pok)' auf 'Gänse [i] .get() == pok' so dass' DelApsClass' nicht schaffen keine 'shared_ptr's . – immibis