4 Stimmen

Kann das Folgende zu Problemen mit dem Gedächtnis führen?

Angenommen, ich habe das Folgende in einer DLL-Implementierung (z. B. würde es eine cpp-Datei haben):

class Base
{
protected:
    Something *some;
public:
    virtual void init()
    {
        some = new Something();
    }

    virtual  ~Base()
    {
        delete some;
    }

};

Dann mache ich in meiner Exe:

class Derived : public Base
{
public:
    virtual void init()
    {
        some = new SomethingElse();
    }
};

int main()
{
   Base *blah = new Derived;
   delete blah;
}

Würde dies jemals Probleme verursachen, wenn die DLL mit einer anderen Laufzeit als die Exe ausgeführt wird?

Wenn ja, gibt es eine nicht Boost, nicht C++ 0x Lösung

Danke

3voto

Nawaz Punkte 339767

Ich denke, Sie müssen schreiben ~Derive() wie diese

~Derived()
{
   delete some;
   some = 0; //this is must; so that `delete some` in ~Base() works perfectly; 
  //note `delete (void*)0` is fine in C++!
}

Erläuterung:

Warum Sie dies schreiben müssen, obwohl die ~Base() macht das Gleiche (es sieht so aus, als ob es das Gleiche tut) ist, weil ~Derived() gewährleistet dass Sie Ihr Objekt aus der Datenbank dieselbe Heap/Speicherpool/etc, auf dem sie erstellt wurden.

Siehe diese Themen:

Wie verwendet man eine Klasse in einer DLL?
Speicherverwaltung mit zurückkehrender char*-Funktion


EDIT :

Besser wäre es, eine weitere virtuelle Funktion hinzuzufügen, etwa deinit() (ein Gegenstück zu Ihrem virtual void init() ), definieren Sie diese ebenfalls neu, wenn Sie die init() und führen Sie die Deallokation dort in deinit() .

//DLL
class Base
{
protected:
    Something *some;
public:
    virtual void init()
    {
        some = new Something();
    }
    virtual void deinit()
    {
        delete some;
    }
    virtual  ~Base() { deinit(); }
};

//EXE
class Derived : public Base
{
public:
    virtual void init()
    {
        some = new SomethingElse();
    }
    virtual void deinit()
    {
        delete some; //some=0 is not needed anymore!
    }
};

0voto

Cine Punkte 3977

Derived zugewiesen some und ist daher weiterhin für die Freigabe verantwortlich. Überschreiben Sie den Destruktor...

Wenn Sie diesen Grundsatz immer befolgen, ist Ihre Speicherverwaltung viel einfacher.

0voto

Zooba Punkte 10867

Es wird keine Probleme geben, obwohl natürlich der Code in Derived wird niemals an die andere ausführbare Datei weitergegeben.

Der Destruktor für Base wird korrekt gelöscht some bereitgestellt Something leitet sich ab von SomethingElse und hat einen virtuellen Destruktor.

0voto

Martin York Punkte 245363

Ich denke, Sie sollten etwas in seinem Konstruktor initialisieren.

Andernfalls löscht der Destruktor einen zufälligen Teil des Speichers.

Base::Base()
    : Something(NULL)
{ }

0voto

Matthieu M. Punkte 266317

Es ist hässlicher Code wegen der protected variabel.

Ich schlage vor, dass wir sie umgestalten. Zunächst sollten wir dafür sorgen, dass die gesamte Eigentumslogik isoliert wird, damit sie leichter zu beweisen ist.

class Base
{
public:
  Base(): some(0) {} // better initialize it...
  virtual ~Base() { delete some; }

  void init() { delete some; some = this->initImpl(); }

private:
  Base(Base const&); // no copy
  Base& operator=(Base const&); // no assignment

  virtual SomeType* initImpl() { return new SomeType(); }

  SomeType* some;
}; // class Base

class Derived: public Base
{
  virtual SomeOtherType* initImpl() { return new SomeOtherType(); }
};

Das ist aber nur ein erster Schritt, denn Sie sollten nicht versuchen, Ressourcen direkt zu manipulieren, denn das würde nur dazu führen, dass sie verloren gehen. Jetzt nehmen wir also unsere glänzende Schnittstelle und formen die Implementierung um:

// something that you should definitely have for your base classes
class noncopyable { protected: noncopyable() {} private: noncopyable(noncopyable const&); noncopyable& operator=(noncopyable const&); };

class Base: noncopyable
{
public:
  Base() {}
  virtual ~Base() {}

  void init() { some.reset(this->initImpl()); }

private:
  virtual SomeType* initImpl() { return new SomeType(); }

  std::auto_ptr<SomeType> some;
}; // class Base

// same Derived class, that's the beauty of insulation :)

Ist das nicht viel besser?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X