2

Also habe ich eine Basisklasse bekam die wie folgt aussieht:Gibt es eine Möglichkeit, Speicherlecks in einer abgeleiteten Klasse zu verhindern, ohne die Basisklasse zu ändern?

class base { 
public: 
    base() { 
     std::cout << "We created a base!" << std::endl; 
    } 

    ~base() { 
     std::cout << "We destroyed a base!" << std::endl; 
    } 
}; 

Und ich habe eine abgeleitete Klasse, die wie folgt aussieht:

class leaks_memory : public base { 
public: 
    leaks_memory(size_t count) : 
    memory(new int[count]), size_of_memory(count) 
    { 
     announce(); 
    } 

    leaks_memory(const leaks_memory & lm) : 
    leaks_memory(lm.size_of_memory) 
    { 
     std::copy(lm.memory, lm.memory + size_of_memory, memory); 
    } 

    void swap(leaks_memory & lm) noexcept { 
     std::swap(lm.memory, memory); 
     std::swap(lm.size_of_memory, size_of_memory); 
    } 

    leaks_memory(leaks_memory && lm) { 
     swap(lm); 
    } 

    leaks_memory & operator=(leaks_memory lm) { 
     swap(lm); 
     return *this; 
    } 

    ~leaks_memory() { 
     delete[] memory; 
     dennounce(); 
    } 

    int & operator[](size_t index) { 
     return memory[index]; 
    } 

    const int & operator[](size_t index) const { 
     return memory[index]; 
    } 
private: 
    int * memory; 
    size_t size_of_memory; 

    void announce() const noexcept { 
     std::cout << "We created a Leaks Memory!" << std::endl; 
    } 

    void dennounce() const noexcept { 
     std::cout << "We destroyed a Leaks Memory!" << std::endl; 
    } 
}; 

Nun sind diese nicht, auf ihre eigenen Fragen, bis ich Code schreiben, der wie folgt aussieht:

int main() { 
    std::unique_ptr<base> base_ptr; 
    std::atomic_bool done = false; 
    std::thread input_thread{ [&done] { 
     std::getline(std::cin, std::string()); 
     done = true; 
    } }; 
    while (!done) { 
     base_ptr = std::make_unique<leaks_memory>(20'000); 
    } 
    input_thread.join(); 
    return 0; 
} 

Dieser Code Lecks jede Iteration der Schleife 20KB, weil die leaks_memory destructor nie aufgerufen wird!

Nun, natürlich, ich könnte dieses Problem beheben, indem bearbeitet zu base machen:

virtual ~base() { 
     std::cout << "We destroyed a base!" << std::endl; 
    } 

Und in der Tat, wenn ich den gleichen Code nach dieser Änderung laufen, ich habe nicht mehr dieses Speicherleck.

Aber was ist, wenn ich in einer Situation bin, in der ich die Klasse base nicht bearbeiten kann? Gibt es eine Möglichkeit, den Speicherverlust zu verhindern, ohne das Design des ausführenden Codes vollständig zu ändern?

+3

Haben Sie einen 'virtuellen' Destruktor in der Basisklasse. –

+1

@ πάνταῥεῖ Bitte lesen Sie die gesamte Eingabeaufforderung. Ich möchte wissen, ob es möglich ist * ohne * die Basisklasse zu modifizieren. Ich weiß bereits, dass es einen Fehler machen wird, den Destruktor virtuell zu machen. – Xirema

+0

@ πάνταῥεῖ BTW-Destruktoren sollten immer virtuell sein. –

Antwort

2

C++ 11 intelligente Zeiger haben benutzerdefinierte Löscher, die die Anforderung, ein virtuelles Destruktot an einer Wurzel jeder Hierarchie zu haben, etwas lockern.

Leider ist diese Funktion nicht einfach zu verwenden, da der Typ des Löschers ein Vorlagenparameter von shared_ptr und unique_ptr ist. Also, um die Art des endgültigen Objekt zu verbergen, muss man ein bisschen Typ Löschung:

void derived_deleter(base* p) { delete static_cast<derived*>(p); } 

std::unique_ptr<base, decltype(&derived_deleter)> base_ptr (new derived, derived_deleter); 

Es scheint keine Möglichkeit zu geben std :: make_unique zu verwenden.

+0

Das funktioniert gut mit 'base_ptr (nullptr, nullptr)' und dann 'base_ptr.swap (temp_base_ptr)' in der Schleife. – wally

0

Eine weitere Option, wenn Sie mit einer const Referenz leben können, könnte die "most important const"

In dem folgenden zu verwenden sein wird, einen Verweis auf die Basis schaffen, sondern wird das abgeleitete destructor nennen.

leaks_memory factory() 
{ 
    return leaks_memory(20'000); 
} 

int main() 
{ 
    //std::unique_ptr<base> base_ptr; 
    std::atomic_bool done = false; 
    std::thread input_thread{[&done] { 
     std::getline(std::cin, std::string()); 
     done = true; 
    }}; 
    while (!done) { 
     //base_ptr = std::make_unique<leaks_memory>(20'000); 
     const base& base_const_ref = factory(); 
    } 
    input_thread.join(); 
    return 0; 
}