Standardcontainer kapseln



  • Hallo Forum,

    ich bin dabei, mir einen kleinen FIFO-Container zu bauen, der eine feste Maximalgröße hat. Wird durch ein push die Maximalgröße überschritten, soll ein "auto-pop" erfolgen, es soll also das älteste Element einfach aus dem Container gelöscht werden.
    Zudem hätte ich gerne die Möglichkeit, über die Elemente des Containers zu iterieren. Mein Gedanke war nun, einen Standardcontainer zu kapseln und ggf. die erforderliche Funktionalität einfach "durchzureichen".

    Hier mein bisheriger Entwurf:

    template<typename T, std::size_t N>
    class limited_size_queue
    {
    public:
       auto begin(); // exemplarisch
    
       void push(T&& val);
       void pop();
    
    private:
       std::list<T>  m_data;
    };
    
    template<typename T, std::size_t N>
    void limited_size_queue<T, N>::push(T&& val)
    {
       m_data.push_back(std::forward<T>(val));
    
       // perform auto-pop when container-size is exceeded
       if (m_data.size() > N)
          m_data.pop_front();
    }
    
    template<typename T, std::size_t N>
    void limited_size_queue<T, N>::pop()
    {
       m_data.pop_front();
    }
    
    template<typename T, std::size_t N>
    auto limited_size_queue<T, N>::begin()
    {
       return m_data.begin();
    }
    
    • Ich denke, push und auto-pop sollten so passen. Falls nicht, bitte gerne Verbesserungen vorschlagen.
    • Was die Iteratoren angeht, hätte ich einfach alle Iteratoren, die die std::list bietet, so wie oben exemplarisch für "begin" durchgereicht. Passt das so?

    Für eher kleine Containergrößen fände ich es dann noch schön, wenn ich über geschweifte Klammern initialisieren könnte:

    limited_size_queue<double, 3> foo { 1.0, 2.0, 3.0 };
    

    Wie man das realisiert, ist mir allerdings ziemlich unklar. Könnte mir diesbezüglich jemand ein paar Hinweise geben?

    Vielen Dank vorab.



  • Klingt wie ein "RingBuffer" was du da hast.
    https://en.wikipedia.org/wiki/Circular_buffer



  • Für das Initialisieren mittels { ... } gibt es std::initializer_list.



  • @It0101 sagte in Standardcontainer kapseln:

    Klingt wie ein "RingBuffer" was du da hast.
    https://en.wikipedia.org/wiki/Circular_buffer

    Joa, jetzt wo ich mir das so durchlese, glaube ich das auch. Wenn ich Informatiker wäre, hätte ich davon vermutlich im Studium schon mal gehört 🙂 Danke für den Hinweis! Da kann mein Ansatz bezüglich Performance sicher noch ein wenig profitieren. Entweder ich übe ein bisschen oder ich suche mir was Fertiges.

    @Th69 sagte in Standardcontainer kapseln:

    Für das Initialisieren mittels { ... } gibt es std::initializer_list.

    Da hätte ich auch selbst drauf kommen dürfen. Aber das hilft mir weiter, danke.
    Dann werde ich mir noch überlegen müssen wie ich damit umgehe, wenn die Anzahl der Elemente der initializer_list nicht zur Containergröße passt.



  • @LennyS
    Ein Ringpuffer ist nicht allzu schwer zu bauen.
    Du hast N Element ( z.B. als vector ).
    Und du hast eine Schreibposition und eine Leseposition.
    Immer wenn du etwas auslesen willst gehst du zur aktuellen Leseposition liest das Element aus und erhöhst.
    Dito für Schreiben. Und wenn du dann noch drauf achtest, dass die Leseposition die Schreibposition nicht überholt, bist du auch schon fertig 😉 Auch ein guter Anwendungsfall für "std::move".







  • @5cript sagte in Standardcontainer kapseln:

    Und für die boost liebhaber:
    https://www.boost.org/doc/libs/1_61_0/doc/html/circular_buffer.html

    Die boost-Version habe ich gefunden, darf ich aber leider nicht verwenden. Danke trotzdem für den Hinweis.

    @It0101 sagte in Standardcontainer kapseln:

    @LennyS
    Ein Ringpuffer ist nicht allzu schwer zu bauen.
    Du hast N Element ( z.B. als vector ).
    Und du hast eine Schreibposition und eine Leseposition.
    Immer wenn du etwas auslesen willst gehst du zur aktuellen Leseposition liest das Element aus und erhöhst.
    Dito für Schreiben. Und wenn du dann noch drauf achtest, dass die Leseposition die Schreibposition nicht überholt, bist du auch schon fertig 😉 Auch ein guter Anwendungsfall für "std::move".

    @It0101 sagte in Standardcontainer kapseln:

    Selbstbau wird hier betrieben:
    https://embeddedartistry.com/blog/2017/4/6/circular-buffers-in-cc

    Für meinen Anwendungsfall reicht eine relativ schlanke Version und die ist auf jeden Fall hinzubekommen. Anregungen und Vorlagen finden sich dann doch einige, wenn man mal weiß, nach welchem Begriff man suchen muss.



  • @LennyS
    In dem Fall rate ich dir zum Selbstbau. Wenn Performance ein Thema ist, ist es natürlich etwas aufwändiger.
    Am besten gleich noch mit Unit-Test, um eventuelle Fehler frühzeitig zu erkennen.

    Fange einfach mal an und wenn du ins Stocken gerätst kannst du ja hier fragen 😉


Anmelden zum Antworten