RAI vs std::unique_ptr
-
Hallo,
ich sehe immer wieder Code, wo statt RAI std::unique_ptr als Member-Variablen verwendet werden.class foo { public: foo(); // Instanziierung von Member-Variablen ~foo(); // Bei Raw-Pointern wird hier delete gemacht private: std::unique_ptr<bla> bla_instance; }
Ich sehe das nicht wirklich als nötig an, deshalb frage ich mich, wo hier der Vorteil ist.
Ich sehe da sogar Nachteile, da bei Vorwärtsdeklarationen auch noch eine Funktion für das Delete mitgegeben werden muss, während man das bei Roh-Pointern nicht machen muss.Wie seht ihr das?
-
Statt RAII? Das ist doch der beste Ausdruck von RAII, Ressourcen einem dafür vorgesehenen Handler zu übergeben. Kann man nichts mehr falsch machen, und spart Unmengen unnötigen Boilerplatecodes, der sonst nur das wiederholen würde, was die Handlerklasse macht. Siehe Stichwort: Rule of 0
-
@SeppJ sagte in RAI vs std::unique_ptr:
Statt RAII? Das ist doch der beste Ausdruck von RAII, Ressourcen einem dafür vorgesehenen Handler zu übergeben. Kann man nichts mehr falsch machen, und spart Unmengen unnötigen Boilerplatecodes, der sonst nur das wiederholen würde, was die Handlerklasse macht. Siehe Stichwort: Rule of 0
Ich weiß nicht, ob wir vom selben Reden. Im obigen Beispiel hätte ich bla_instance als Roh-Pointer nehmen können und hätte mit RAI alles abgedeckt. Ein std::unique_ptr wäre vollkommen unnötig gewesen. Wozu nehmen hier manche std::unique_ptr?
-
Hier wird gar nichts deleted wenn du einen rohen Pointer verwendest - genau das man der unique_ptr - er hat keinen anderen Lebenszweck
Natürlich wird bei delete foo-Zeiger dein foo-dtor aufgerufen aber eben nicht der von bla
Rohe Zeiger haben keinen Scope
-
@Steffo sagte in RAI vs std::unique_ptr:
hätte mit RAI alles abgedeckt.
Du hättest schon die 5er Regel nicht erfüllt.
-
This post is deleted!
-
@Steffo sagte in RAI vs std::unique_ptr:
Ich sehe da sogar Nachteile, da bei Vorwärtsdeklarationen auch noch eine Funktion für das Delete mitgegeben werden muss,
Den Satz verstehe ich nicht.
-
@manni66
Steffo braucht noch ein bisschem um die Frage umzuformulieren oder bis er sich klar darüber ist das er in seinem Projekten ganz viele Memory-Leaks hat
-
@Steffo sagte in RAI vs std::unique_ptr:
Ich weiß nicht, ob wir vom selben Reden. Im obigen Beispiel hätte ich bla_instance als Roh-Pointer nehmen können und hätte mit RAI alles abgedeckt. Ein std::unique_ptr wäre vollkommen unnötig gewesen. Wozu nehmen hier manche std::unique_ptr?
Wegen dem Single Responsibility Principle -- eine Klasse sollte nur eine Aufgabe haben. Deine Klasse hat zusätzlich zu ihrer eigentlichen Aufgabe noch die Aufgabe, eine Resource zu verwalten. Mit unique_ptr übernimmt das eine andere Klasse.
Es heißt übrigens RAII.
-
Hier mal ein vollständiges Beispiel, wie man das mit RAI macht:
class foo { public: foo() { bla = new bla(); } ~foo() { delete bla; } private: bla* bla_instance; }
Zurück zu meiner Ausgangsfrage
Wozu std::unique_ptr?
-
foo f1; foo f2; f1 = f2; // Bumm
-
Das ist aber kein RAII - weil du deinen Speicher "von Hand" aufräumst
Online-Testen: cpp.sh/4w6ds
#include <iostream> #include <memory> struct test { test(){ std::cout << "test.ctor" << std::endl; } ~test(){ std::cout << "test.dtor" << std::endl; } }; struct test2 { test2():t(new test()){} std::unique_ptr<test> t; }; struct test3 { test3():t(new test()){} test* t; }; int main() { test2(); test3(); }
Ausgabe:
test.ctor
test.dtor
test.ctor
-
Naja, er macht schon sowas wie RAII. Nur halt manuell und unvollständig. Wenn er das fehlerfrei und vollständig komplettiert hat er aber genau das, was
std::unique_ptr
macht. Und dann kann man sich natürlich fragen, warum man den nicht sofort benutzt hat.
-
@llm sagte in RAI vs std::unique_ptr:
Das ist aber kein RAII - weil du deinen Speicher "von Hand" aufräumst
Online-Testen: cpp.sh/4w6ds
#include <iostream> #include <memory> struct test { test(){ std::cout << "test.ctor" << std::endl; } ~test(){ std::cout << "test.dtor" << std::endl; } }; struct test2 { test2():t(new test()){} std::unique_ptr<test> t; }; struct test3 { test3():t(new test()){} test* t; }; int main() { test2(); test3(); }
Ausgabe:
test.ctor
test.dtor
test.ctortest3 hat ja auch ein Leak. Bevor es std::unique_ptr gab, ist man doch genau so vorgegangen und nannte das RAII, oder nicht?
-
Klar - aber der unique_ptr forciert das RAII Konzept für Heap-Dinge
-
@manni66 sagte in RAI vs std::unique_ptr:
foo f1; foo f2; f1 = f2; // Bumm
Nicht wirklich: http://cpp.sh/8rzfo
-
@Steffo sagte in RAI vs std::unique_ptr:
Nicht wirklich:
Doch wirklich. Memory leak und double free.
-
@manni66 sagte in RAI vs std::unique_ptr:
@Steffo sagte in RAI vs std::unique_ptr:
Ich sehe da sogar Nachteile, da bei Vorwärtsdeklarationen auch noch eine Funktion für das Delete mitgegeben werden muss,
Den Satz verstehe ich nicht.
Das hier funktioniert nicht.
// Vorwärtsdeklaration class bla; class foo { public: foo(); // Instanziierung von Member-Variablen ~foo(); // Bei Raw-Pointern wird hier delete gemacht private: std::unique_ptr<bla> bla_instance; }
-
-
@manni66 sagte in RAI vs std::unique_ptr:
@Steffo
In die cppfoo::~foo() = default;
und schon geht's.
Ich kann dir wirklich nicht folgen. Es kompiliert und der Konstruktor wird zwei mal aufgerufen: