Smart Pointer statt 'new' und 'delete'?



  • Habe vor einigen Tagen gelesen, dass man in C++11 kein new und delete mehr verwendet werden sollte, um Speicher auf dem Heap zu allokieren ("schlechter Stil"). Leider finde ich den Link nicht mehr.

    Wenn man keinen std::vector verwenden möchte, wie allokiere ich dynamisch Speicher via Smart Pointer anstatt mit new und delete?

    Sorry wegen der naiven Frage?

    😕



  • Reicht ein Wikipedia Link ?





  • wenn du mehrere elemente willst: container wie std::vector , std::list , std::forward_list , std::deque , std::map (inkl. unordered- / multi-varianten) oder std::set (ebenfalls inkl. unordered- / multi-varianten).

    wenn du nur ein element willst und das auf dem heap sein sollte: std::unique_ptr , std::weak_ptr oder selten mal std::shared_ptr ( std::auto_ptr ist deprecated und nicht intuitiv). in c++03 kann man bei smart-pointern nicht auf new verzichten (auf delete aber schon!). für std::shared_ptr gibt es std::make_shared . mit c++14 wird dann endlich std::make_unique eingeführt.

    http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique



  • kein new und delete mehr verwendet werden sollte

    Daumeregel: ja! Aber manchmal kommt es drauf an ... . Ich hoffe du hast verstanden, warum. Denn eine Regel zu befolgen, ohne zu verstehen ist wesentlich schlimmer. new wirst du aber im Zusammenhang mit smart pointer trotzdem noch benutzen.

    Ich finde http://klmr.me/slides/modern-cpp.pdf viel zu plakativ. Ich nutze Zeiger weiterhin sehr oft.



  • wenn du mehrere elemente willst: container wie std::vector, std::list, std::forward_list, std::deque, std::map (inkl. unordered- / multi-varianten) oder std::set (ebenfalls inkl. unordered- / multi-varianten).

    Naja aber das allein reicht auch nur dann aus wenn man die Objekte selber in dem Container speichert. Das ist allerdings nicht immer erwünscht, wenn man nur einen Zeiger speichern will braucht man auch hier unique_ptr/shared_ptr.



  • DarkShadow44 schrieb:

    wenn du mehrere elemente willst: container wie std::vector, std::list, std::forward_list, std::deque, std::map (inkl. unordered- / multi-varianten) oder std::set (ebenfalls inkl. unordered- / multi-varianten).

    Naja aber das allein reicht auch nur dann aus wenn man die Objekte selber in dem Container speichert. Das ist allerdings nicht immer erwünscht, wenn man nur einen Zeiger speichern will braucht man auch hier unique_ptr/shared_ptr.

    Immer wenn ich einen smartpointer in einem Container sehe, dann graust es mir.
    Wir haben boost pointer container dafür.



  • DarkShadow44 schrieb:

    wenn du mehrere elemente willst: container wie std::vector, std::list, std::forward_list, std::deque, std::map (inkl. unordered- / multi-varianten) oder std::set (ebenfalls inkl. unordered- / multi-varianten).

    Naja aber das allein reicht auch nur dann aus wenn man die Objekte selber in dem Container speichert. Das ist allerdings nicht immer erwünscht, wenn man nur einen Zeiger speichern will braucht man auch hier unique_ptr/shared_ptr.

    dann nimmt man ptr_vector aus boost.



  • Habe vor einigen Tagen gelesen, dass man in C++11 kein new und delete mehr verwendet werden sollte

    1. die Thematik betrifft nicht nur c++ ab C++11, sondern war auch vorher schon aktuell
    2. Formulierung 🙂 man sollte kein "rohes" new und delete verwenden. Auch in verbindung mit smartpointer kommst um new nicht drumherum, und das delete wird nur automatisch gecallt.

    Wenn man keinen std::vector verwenden möchte, wie allokiere ich dynamisch Speicher via Smart Pointer anstatt mit new und delete?

    Frage: warum kein std::vector ? der bietet sich doch förmlich an, wenn man Speicher für einen zusammenhängenden bereich von gleichartigen Daten allokieren muss ?

    smartpointer sind eher für einzelne Objecte aufn Heap, als für arrays gedacht.

    Allerdings soll
    std::unique_ptr<int[]> myptr(new int[9]);
    so ueberladen, sein, das er correct das delete[] statt dem normalen delete aufruft.
    Aber ehrlich, warum sollt man das so machen?
    was wäre der Vorteil gegenüber std::vector<int> myArray(9,0); ???

    Ciao ...



  • RHBaum schrieb:

    Allerdings soll
    std::unique_ptr<int[]> myptr(new int[9]);
    so ueberladen, sein, das er correct das delete[] statt dem normalen delete aufruft.
    Aber ehrlich, warum sollt man das so machen?
    was wäre der Vorteil gegenüber std::vector<int> myArray(9,0); ???

    mir fällt da nur ein dass std::vector in der regel 2 * sizeof(std::size_t) mehr speicher braucht (für size und reserve ) und in vielen implementierungen in zweierpotenzen alloziert. diese beiden eigenschaften *könnten* in randfällen unerwünscht sein (mir fällt keiner ein im moment). aber im allgemeinen hast du recht.



  • asfdlol schrieb:

    RHBaum schrieb:

    Allerdings soll
    std::unique_ptr<int[]> myptr(new int[9]);
    so ueberladen, sein, das er correct das delete[] statt dem normalen delete aufruft.
    Aber ehrlich, warum sollt man das so machen?
    was wäre der Vorteil gegenüber std::vector<int> myArray(9,0); ???

    mir fällt da nur ein dass std::vector in der regel 2 * sizeof(std::size_t) mehr speicher braucht (für size und reserve ) und in vielen implementierungen in zweierpotenzen alloziert. diese beiden eigenschaften *könnten* in randfällen unerwünscht sein (mir fällt keiner ein im moment). aber im allgemeinen hast du recht.

    Wobei das ja so ist, das die Allokation in zweierpotenzen nur dann zum tragen kommt, wenn man vorher nicht weiß, wie viele Elemente man einfügen möchte. In diesen Fällen hilft einem aber das new int[9] auch nichts und zur Not kann man immer noch ein shrink_to_fit machen.



  • Immer wenn ich einen smartpointer in einem Container sehe, dann graust es mir.
    Wir haben boost pointer container dafür.

    Und wenn man nun aber keine Abhängigkeit von boost will ? 🙄



  • DarkShadow44 schrieb:

    Immer wenn ich einen smartpointer in einem Container sehe, dann graust es mir.
    Wir haben boost pointer container dafür.

    Und wenn man nun aber keine Abhängigkeit von boost will ? 🙄

    Das ist einfach nur eine billige Ausrede um es falsch zu machen.
    Wir haben auch Smartpointer lange vorher verwendet bevor es sie im Standard gab.

    Der korrekte Weg Zeiger in einem container zu speichern sind pointer container, ob diese jetzt von boost kommen, selber geschrieben sind oder aus dem Ausland importiert wurden ist dabei egal.

    Never ever einen Smartpointer in einen Container packen - das ist nur Faulheit.

    Es gibt Situationen wo man einen shared_ptr in einem Container haben will (sehr sehr wenige) aber es gibt NIE eine Situation wo man einen unique_ptr haben will.



  • asfdlol schrieb:

    mir fällt da nur ein dass std::vector in der regel 2 * sizeof(std::size_t) mehr speicher braucht (für size und reserve ) und in vielen implementierungen in zweierpotenzen alloziert. diese beiden eigenschaften *könnten* in randfällen unerwünscht sein (mir fällt keiner ein im moment). aber im allgemeinen hast du recht.

    Selbst das bekommst du hin, wenn du vor jedem push_back size() gegen capacity() prüfst und ggf. mit resize() hinten Platz für neue Elemente reservierst.

    Was mich bei dieser stereotypen Predigt immer stört ist, dass der Kontext nicht berücksichtigt wird. Sobald man Objekthierachien verwalten muss, bei denen Objekte über Zeiger in Beziehung stehen funktioniert ein besitzender vector ohne (smart_) pointer einfach nicht mehr. Aber irgendwie wird hier immer davon ausgegangen, dass man einfach nur eine Menge von Objekten verwalten muss, die mit nichts in Relation stehen.



  • Shade Of Mine schrieb:

    Der korrekte Weg Zeiger in einem container zu speichern sind pointer container, ob diese jetzt von boost kommen, selber geschrieben sind oder aus dem Ausland importiert wurden ist dabei egal.

    Du willst tatsächlich sagen, dass es besser ist einen vector von Pointern von grund auf neu zu implementieren, anstatt einen stl:vector mit smartpointern zu nehmen?



  • Shade Of Mine schrieb:

    Es gibt Situationen wo man einen shared_ptr in einem Container haben will (sehr sehr wenige) aber es gibt NIE eine Situation wo man einen unique_ptr haben will.

    Kannst du das bitte etwas näher erläutern?



  • Zeiger speichern will braucht man auch hier unique_ptr/shared_ptr.

    Wenn ich Zeiger speichern will, dann nutze ich Zeiger.

    Was mich an std::vector manchmal stoert, ist: er initialisiert den Speicher bzw. ruft den Konstruktor auf. Bei primitiven Datentypen/PODs manchmal unerwuenscht.



  • @TNA:
    Ja, die halbe Stunde arbeit wirst du schon hinbekommen. Man kann das ja auch als container adapter implementieren. Ist ja keine Hexerei. Echt nicht.

    @Skym0sh0:
    unique_ptr in einem Container bedeutet, dass man einen pointer container haben will - da der Container der Besitzer ist. Das erspart eine Menge Verwaltungsaufwand es einfach den Container anzuschaffen - denn der weiß ja alles was er wissen muss. Er kann dann auch eine viel bequemere Syntax anbieten.

    shared_ptr dagegen können theoretisch Sinn machen, da diese ja Aussagen "ich weiß nicht wer der Besitzer ist". So könnte es sein, dass man einfach solche Objekte in einen Container packen will und wieder entfernen - die Lebenszeit des Objektes aber nicht direkt mit dem Container gekoppelt ist.

    Das kommt sehr selten vor - ich denke dass shared_ptr generell sehr sehr sehr selten verwendet werden sollte, denn wie gesagt: shared_ptr heisst: Ich weiß nicht bzw. es interessiert mich nicht wer der Besitzer ist. Das sollte die Ausnahme und nicht die Regel sein. Da Besitzrechte klar geklärt gehören.



  • Shade Of Mine schrieb:

    @TNA:
    Ja, die halbe Stunde arbeit wirst du schon hinbekommen.

    Dein Vertrauen ehrt mich, aber ich würde mir nie zutrauen, in einer halben Stunde Code in "STL-Qualität" zu erstellen.

    Shade Of Mine schrieb:

    Man kann das ja auch als container adapter implementieren. Ist ja keine Hexerei. Echt nicht.

    Das hört sich eher nach einer brauchbaren Lösung an.



  • Shade Of Mine schrieb:

    @Skym0sh0:
    unique_ptr in einem Container bedeutet, dass man einen pointer container haben will - da der Container der Besitzer ist. Das erspart eine Menge Verwaltungsaufwand es einfach den Container anzuschaffen - denn der weiß ja alles was er wissen muss.

    Wieso?
    Meistens will ich doch einen PointerContainer, um Polymorphie zu nutzen. Ich stecke viele unterschiedliche Objekte mit gleichem Interface rein. Klar, der Container ist der Besitzer, aber ein unique_ptr im Container würde es doch genauso tun.
    (Überzeug mich!)

    Shade Of Mine schrieb:

    shared_ptr dagegen können theoretisch Sinn machen, da diese ja Aussagen "ich weiß nicht wer der Besitzer ist". So könnte es sein, dass man einfach solche Objekte in einen Container packen will und wieder entfernen - die Lebenszeit des Objektes aber nicht direkt mit dem Container gekoppelt ist.

    Das kommt sehr selten vor - ich denke dass shared_ptr generell sehr sehr sehr selten verwendet werden sollte, denn wie gesagt: shared_ptr heisst: Ich weiß nicht bzw. es interessiert mich nicht wer der Besitzer ist. Das sollte die Ausnahme und nicht die Regel sein. Da Besitzrechte klar geklärt gehören.

    Keine Frage. Dem ist so!


Log in to reply