Destructor wird nicht gerufen bei lazy-init Code-Beispiel - und Lösung
-
Hi,
zunächst einmal der Code infrage:
// wer damit experimentieren möchte: https://onlinegdb.com/UZV0zfRdCT #include <iostream> #include <list> class App { public: virtual const char* getName() = 0; }; class AppWatch: public App { public: AppWatch() { std::cout << "created " << this->getName() << std::endl; } virtual ~AppWatch() { std::cout << "destroyed " << this->getName() << std::endl; } const char* getName() override { return "watch"; }; }; class AppTool: public App { public: AppTool() { std::cout << "created " << this->getName() << std::endl; } virtual ~AppTool() { std::cout << "destroyed " << this->getName() << std::endl; } const char* getName() override { return "tool"; }; }; class LazyInit { public: LazyInit() { std::cout << "lazy yay" << std::endl; } template<typename T> void set() { this->init = []() -> App* { return new T(); }; } App* operator->() { if(this->ptr == nullptr) this->ptr = this->init(); return this->ptr; } virtual ~LazyInit() { if(this->ptr) { std::cout << "lazy death with " << (size_t) this->ptr << std::endl; delete this->ptr; } else std::cout << "lazy death" << std::endl; } private: App* (*init)() = nullptr; App* ptr = nullptr; }; std::list<LazyInit> test; int main() { std::cout << "** Test start" << std::endl; { AppTool at; } std::cout << "** Test done" << std::endl; std::cout << "** Test start" << std::endl; { LazyInit lazy; lazy.set<AppWatch>(); std::cout << "**Test prepared" << std::endl; lazy->getName(); // do smth with lazy object } std::cout << "** Test done" << std::endl; std::cout << "** Test start" << std::endl; { LazyInit lazy; lazy.set<AppWatch>(); test.emplace_back(lazy); std::cout << "**Test prepared" << std::endl; test.back()->getName(); // do smth with lazy object test.clear(); } std::cout << "** Test done" << std::endl; return 0; }
Das Ziel soll es sein, dass das "LazyInit-Object" erst bei Dereferenzierung die entsprechende Klasse erzeugt. Das funktioniert auch so weit - das Problem ist, dass der Destructor der AppTool/AppWatch nicht korrekt ausgeführt wird, wenn "delete this->ptr;" erreicht wird (obwohl die Destructoren der Child-Klassen "virtual" sind).
Lösung
Tjaa, manchmal muss man das Problem nur Aufschreiben - die Lösung ist es ebenfalls den Destructor der "App"-Klasse auf "virtual" zu setzen, da ansonsten nicht in der vtable nachgeprüft wird, ob weitere Destructoren fehlen.Ich lasse den Beitrag mal online - ggf. stolpert wer anderes ebenfalls über diese Feinheit
-
@Simonmicro sagte in Destructor wird nicht gerufen bei lazy-init Code-Beispiel - und Lösung:
die Lösung ist es ebenfalls den Constructor der "App"-Klasse auf "virtual" zu setzen
Destructor
-
@hustbaer Well, you've got me there - fixed it