Wofür habt ihr std::list benutzt?



  • Mich würde mal interessieren, was mit std::list so gemacht wird. Der Container hat bestimmte Eigenschaften, die vector nicht bieten kann. Es gibt bestimmt Fälle, in denen diese Eigenschaften die Verwendung von list rechtfertigen. Habt ihr konkrete Beispiele, in denen list weniger fehleranfällig, besser lesbar oder schneller ist als vector ?



  • TyRoXx schrieb:

    Mich würde mal interessieren, was mit std::list so gemacht wird. Der Container hat bestimmte Eigenschaften, die vector nicht bieten kann. Es gibt bestimmt Fälle, in denen diese Eigenschaften die Verwendung von list rechtfertigen. Habt ihr konkrete Beispiele, in denen list weniger fehleranfällig, besser lesbar oder schneller ist als vector ?

    Hab sie nie benutzt.



  • Vor allem, wenn ich stabile Objekte brauche (Zeiger und Referenzen auf Elemente bleiben gültig).

    Es gibt inzwischen aber auch spezialisierte Container wie boost::stable_vector .



  • Nexus schrieb:

    Vor allem, wenn ich stabile Objekte brauche (Zeiger und Referenzen auf Elemente bleiben gültig).

    Es gibt inzwischen aber auch spezialisierte Container wie boost::stable_vector .

    das klingt für mich nach einer std::deque.



  • otze schrieb:

    das klingt für mich nach einer std::deque.

    std::deque ist nur beim Einfügen an den Enden stabil.



  • Nexus schrieb:

    otze schrieb:

    das klingt für mich nach einer std::deque.

    std::deque ist nur beim Einfügen an den Enden stabil.

    [c]std::deque[/c] ist gleich stabil beim einfügen am anfang sowie am ende.

    edit: unnötig verbessert da ich nicht richtig gelesen hab.



  • Nexus schrieb:

    Vor allem, wenn ich stabile Objekte brauche (Zeiger und Referenzen auf Elemente bleiben gültig).

    Meine typische Lösung ist da immer ein unique_ptr , den ich in irgendeinen Container wie unordered_map stopfe. So muss ich nicht viel beachten, wenn ich die Erzeugung des Objektes vom Einfügen in den Container trennen möchte. emplace mag ich nicht so, weil es die Erzeugung des Objektes mit dem Einfügen in den Container untrennbar verbindet. Das Objekt einer meiner Klassen zwischen Erzeugung und Einfügen durch die Gegend zu moven ist mir zu gefährlich, weil ich doch recht oft this an Callbacks binde, auch mal in einem Konstruktor. Das ist wahrscheinlich eine schlechte Idee, aber ich weiß es noch nicht besser.

    Je mehr ich Code refaktoriere, desto mehr Lambdas, function s und boost::signals kommen vor. virtual wird seltener. Als Container benutze ich fast nur noch vector und unordered_map . shared_ptr kommt auch vor, aber viel seltener als unique_ptr .



  • TyRoXx schrieb:

    Je mehr ich Code refaktoriere, desto mehr Lambdas, function s und boost::signals kommen vor.

    Oh, das ist bei mir gerade andersrum, ich mache die beim Aufräumen weg(!), unnamed ist unverstanden.

    TyRoXx schrieb:

    Als Container benutze ich fast nur noch vector und unordered_map .

    Jup, ich auch, seit immer. Und noch den Heap/priorityqueue (und niemals map) und noch std::forward_map (bis neulich halt eigenen schmalen Code, nu ist alles im standard.)

    Also
    Vector //Fast alles 99%
    Heap //Der Rest, map sucht ja eh fast immer nur top 0.5%
    Hashtable //Eben wenn mal nicht map/top gebraucht wird 0.5%
    StackAsList //In Kombination mit anderen als Nachstufe.
    QueueAsList oder deque als Verzörerer, wenn der Algo es braucht.



  • asfdlol schrieb:

    Nexus schrieb:

    otze schrieb:

    das klingt für mich nach einer std::deque.

    std::deque ist nur beim Einfügen an den Enden stabil.

    std::deque ist gleich stabil beim einfügen am anfang sowie am ende.

    Steht doch da: "an den Enden". Das heisst am vorderen und am hinteren Ende.
    Beim Einfügen/Löschen in der mitte is aber nix mehr stabil.



  • hustbaer schrieb:

    asfdlol schrieb:

    Nexus schrieb:

    otze schrieb:

    das klingt für mich nach einer std::deque.

    std::deque ist nur beim Einfügen an den Enden stabil.

    std::deque ist gleich stabil beim einfügen am anfang sowie am ende.

    Steht doch da: "an den Enden". Das heisst am vorderen und am hinteren Ende.
    Beim Einfügen/Löschen in der mitte is aber nix mehr stabil.

    jo, du hast recht, ich kann nicht richtig lesen. peinlich. ist durchgestrichen.



  • @asfdlol
    Und ich kann nicht richtig schreiben, hab Mitte klein geschrieben. Hihi.

    @TyRoXx
    Ich kann mich nicht erinnern std::list mal verwendet zu haben.

    TyRoXx schrieb:

    Es gibt bestimmt Fälle, in denen diese Eigenschaften die Verwendung von list rechtfertigen. Habt ihr konkrete Beispiele, in denen list weniger fehleranfällig, besser lesbar oder schneller ist als vector ?

    Konkrete Beispiele hab' ich natürlich keine, hab das Teil ja noch nie verwendet.
    Ich könnte mir vorstellen dass std::list gut ist wenn man die Liste verdammt oft ändert, aber kaum jemals liest. Und wenn man liest, immer nur linear durchfährt.

    Persönlich würde ich dann aber auch eher zu ner intrusive List tendieren - bzw. es mir zumindest gut überlegen. Mit emplace kann man in C++11 ja jetzt auch Elemente in eine List reintun ohne dass kopiert werden muss. Da ich aber in der Arbeit noch mit VC2005 arbeiten muss hab ich kein emplace , und dann hat die intrusive List bei Typen die nicht billigst zu kopieren sind wieder die Nase vorne.

    Allerdings müsste der Unterschied Modifizieren >> Lesen schon massiv sein. Wenns nur um stabile Zeiger etc. geht, oder darum dass die Objekte relativ teuer zu kopieren/moven sind, kann man ja auch nen Pointer-Vektor nehmen.



  • Ähnlich wie Nexus: Wenn es wichtig ist, dass Iteratoren bzw. Zeiger und Referenzen auf Listenelemente auch nach Modifikation des Containers gültig bleiben. Beispiel: Liste von Observern, wenn man den Fall unterstützen muss, dass ein Observer sich in Reaktion auf die Notification aus der Liste löscht...

    Seit ich vom typischen Eventsystem abgekommen bin und keine Observerlisten mehr brauche, hatte ich wohl kaum mehr einen Fall, wo ich eine std::list benutzt hätte, zumindest im Moment fällt mir jedenfalls nichts ein...



  • hustbaer schrieb:

    Konkrete Beispiele hab' ich natürlich keine, hab das Teil ja noch nie verwendet.
    Ich könnte mir vorstellen dass std::list gut ist wenn man die Liste verdammt oft ändert, aber kaum jemals liest. Und wenn man liest, immer nur linear durchfährt.

    Zum Linear-Durchfahren taugt alleroffensichtlichst der vector am besten, weil Prozessor, OS, Compiler oder Mensch prefetchen können.

    Der klassische Pseudogrund für die list ist, daß der vector nicht wachsen kann, bzw so viel Zeit beim Wachsen verbrät. Aber man müßte schon mit Gewalt was konstruieren, wo das der Fall ist.

    Dazumal war ein Grund für list, wenn man Nichtkopierbare Sachen wie ostreams ablegen musste.

    Jetzt bleiben mir eigentlich nur komische Fälle, wie wenn die Objekte unglaublich lahm zu moven sind (ach, unique_ptr davor und gut), oder wenn die Objekte erheblich groß sind und fast immer nur 0 oder 1 Element drin (aber dann auch lieber forward_list), finde kein gutes Beispiel.

    Eures mit den langlebigen iteratoren, wäre da size_t nichrt angebraucht? Warum nicht, ah, die Besitzverhältnisse, wahrscheinlich ist die list nur da, um durchlaufen werden zu können, die Besitzer sind aber Andere, sie tun in KOnstruktor/Destruktor ihre Objekte in die list rein/raus. Da drängt sich gleich hustbaers intrusive List auf. Auch bei den Observern normalerweise. Außer vielleicht, man will sich oft (und das wird zu Laufzeit entschieden!) von gegebenenfalls mehreren Objekten observieren lassen (wird auch wieder eine forward_list).



  • volkard schrieb:

    Eures mit den langlebigen iteratoren, wäre da size_t nichrt angebraucht?

    Das hilft dir nichts, wenn die Position des referenzierten Elements sich ändern kann, z.B. weil Elemente aus dem Container gelöscht werden... 😉



  • dot schrieb:

    Seit ich vom typischen Eventsystem abgekommen bin und keine Observerlisten mehr brauche,

    Was verwendest du statt dessen?


Log in to reply