Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Listenklasse/Template

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 < [ 3 ]
010
10.08.2005, 17:11 Uhr
virtual
Sexiest Bit alive
(Operator)


Da ich kurz leerlauf hatte, habe ich mal schnell was geschrieben:
Das wäre in meinen Augen ein Gerüst für eine gute, STL kompatible Liste. Zu beachten ist der im Post zuvor angesprochene Trick mit dem Alloctor: ich muß´an keiner Stelle root nachhalten, welches eine art dummy darstellt, dessen Nachfolger eben das erste und dessen vorgänger das letzte Listenelemnt darstellt.

Ist wie gesagt nur ein gerüst: ich habe keine dtor eingebaut und lediglich einen kleines Subset der Funktionen eingebaut.


C++:
#include <memory>

template<typename T>
class liste {

    struct node {
        node* prev;
        node* next;
        T data;
    
        node(const T& data) :prev(this), next(this), data(data) {
        }    

        void unlink() {
            prev->next = next;
            next->prev = prev;
        }

        void link(node* prev_node) {
            prev = prev_node;
            next = prev_node->next;
            prev->next = this;
            next->prev = this;
        }
    };

    node* root;

public:
    class iterator {
        liste* l;
        node* n;

    public:
        iterator(liste* l=0, node* n=0)    :l(l), n(n) { }

        T& operator * () { return n->data; }
        T* operator -> () { return &n->data; }
        iterator operator ++ (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->next;
            }
            return tmp;
        }
        iterator& operator ++ () {
            if (n) {
                n = n->next;
            }
            return *this;
        }
        iterator operator -- (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->prev;
            }
            return tmp;
        }
        iterator& operator -- () {
            if (n) {
                n = n->prev;
            }
            return *this;
        }
        bool operator != (const iterator& other) const {
            return other.l!=l || other.n!=n;
        }
        bool operator == (const iterator& other) const {
            return other.l==l && other.n==n;
        }
    };

    liste() {
        root = std::allocator<node>().allocate(1, 0);
        root->prev = root->next = root;
    }

    iterator begin() {
        return iterator(this, root->next);
    }

    iterator end() {
        return iterator(this, root);
    }

    void push_front(const T& data) {
        node* n = new node(data);
        n->link(root);
    }

    void push_back(const T& data) {
        node* n = new node(data);
        n->link(root->prev);
    }

    void pop_front() {
        node* n = root->next;
        n->unlink();
        delete n;
    }

    void pop_back() {
        node* n = root->prev;
        n->unlink();
        delete n;
    }

};


--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
10.08.2005, 19:23 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


nich schlecht, muss ich mir mal in ruhe anschaun
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
14.08.2005, 23:09 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


hmm irgendwie steh ich grad aufm schlauch, sollte der iterator bei "erase" const sein oder eher nicht? schliesslich wird er ja verändert, man löscht ja das zugehörige item?
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
14.08.2005, 23:13 Uhr
(un)wissender
Niveauwart


Ist nicht const, kannst dich da an die STL halten.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
14.08.2005, 23:22 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


jo gut dachte ich mir schon, hatte mich nur gefragt warum oliver in seiner klasse dann den dann const gemacht hatte

hmm wie sähe den die erase-funktion bei virtuals klasse aus? irgendwie begreif ich die da nicht so ganz
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
015
14.08.2005, 23:45 Uhr
(un)wissender
Niveauwart


Man könnte es so machen, es fehlt aber bei virtuals Code noch das friend, oder ähnliches, weil man sonst nicht an den node im iterator kommt.


C++:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <stdexcept>

template<typename T>
class liste {

    struct node {
        node* prev;
        node* next;
        T data;
    
        node(const T& data) :prev(this), next(this), data(data) {
        }    

        void unlink() {
            prev->next = next;
            next->prev = prev;
        }

        void link(node* prev_node) {
            prev = prev_node;
            next = prev_node->next;
            prev->next = this;
            next->prev = this;
        }
    };

    node* root;

public:
    class iterator {
        friend class liste;                   //HIER: friend
        liste* l;
        node* n;

    public:
        iterator(liste* l=0, node* n=0)    :l(l), n(n) { }

        T& operator * () { return n->data; }
        T* operator -> () { return &n->data; }
        iterator operator ++ (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->next;
            }
            return tmp;
        }
        iterator& operator ++ () {
            if (n) {
                n = n->next;
            }
            return *this;
        }
        iterator operator -- (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->prev;
            }
            return tmp;
        }
        iterator& operator -- () {
            if (n) {
                n = n->prev;
            }
            return *this;
        }
        bool operator != (const iterator& other) const {
            return other.l!=l || other.n!=n;
        }
        bool operator == (const iterator& other) const {
            return other.l==l && other.n==n;
        }
    };

    liste() {
        root = std::allocator<node>().allocate(1, 0);
        root->prev = root->next = root;
    }

    iterator begin() {
        return iterator(this, root->next);
    }

    iterator end() {
        return iterator(this, root);
    }

    void push_front(const T& data) {
        node* n = new node(data);
        n->link(root);
    }

    void push_back(const T& data) {
        node* n = new node(data);
        n->link(root->prev);
    }

    void pop_front() {
        node* n = root->next;
        n->unlink();
        delete n;
    }

    void pop_back() {
        node* n = root->prev;
        n->unlink();
        delete n;
    }
    
    void erase(iterator i)
    {
       iterator current = begin(), ende = end();
        while(current != i && i != ende) ++current;
        
        if(current == ende) //nicht gefunden
        {
            throw std::invalid_argument("Unknown iterator");
        }
        
        current.n->unlink();
        delete current.n;                        
    }    

};

int main() {
       liste<int> list;
       list.push_back(1);
       list.push_back(2);
       list.push_back(3);
      
       //@virtual: DAs geht nicht, wegen den fehlenden typedefs "iterator_category, usw."
       //std::copy(list.begin(), list.end(), std::ostream_iterator<int>(std::cout, " "));
      
       typedef liste<int>::iterator listIter;
       for(listIter i = list.begin(); i != list.end(); ++i)
       {
           std::cout << *i << " ";
       }
      
       list.erase(++list.begin()) ;
       std::cout << '\n';
      
       for(listIter i = list.begin(); i != list.end(); ++i)
       {
           std::cout << *i << " ";
       }
}


--
Wer früher stirbt ist länger tot.

Dieser Post wurde am 14.08.2005 um 23:49 Uhr von (un)wissender editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
016
15.08.2005, 08:23 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von (un)wissender:

//@virtual: DAs geht nicht, wegen den fehlenden typedefs "iterator_category, usw."
//std::copy(list.begin(), list.end(), std::ostream_iterator<int>(std::cout, " "));


Korrekt, aber es sollte ja auch nur ein Gerüst sein.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
017
15.08.2005, 08:36 Uhr
(un)wissender
Niveauwart


Ok.
Mal zu deiner Homepage: Das Thema Exceptionsicherheit hast du ja nicht schlecht ausgeführt, aber eines vielleicht noch vergessen/nicht erwähnt. Ohne new ist es oft nicht möglich exceptionssicheren Code zu schreiben, da man nicht immer eine Swap-Routine hat. Wenn ein Objekt bspw. zwei andere Objkte enthält, kann man diese nur mittels dynamischem Speicher so kopieren, dass das Objekt konsistent bleibt, da Pointerkopien nicht werfen.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
018
15.08.2005, 08:54 Uhr
FloSoft
Medialer Over-Flow
(Administrator)



Zitat von (un)wissender:
Man könnte es so machen, es fehlt aber bei virtuals Code noch das friend, oder ähnliches, weil man sonst nicht an den node im iterator kommt.


C++:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <stdexcept>

template<typename T>
class liste {

    struct node {
        node* prev;
        node* next;
        T data;
    
        node(const T& data) :prev(this), next(this), data(data) {
        }    

        void unlink() {
            prev->next = next;
            next->prev = prev;
        }

        void link(node* prev_node) {
            prev = prev_node;
            next = prev_node->next;
            prev->next = this;
            next->prev = this;
        }
    };

    node* root;

public:
    class iterator {
        friend class liste;                   //HIER: friend
        liste* l;
        node* n;

    public:
        iterator(liste* l=0, node* n=0)    :l(l), n(n) { }

        T& operator * () { return n->data; }
        T* operator -> () { return &n->data; }
        iterator operator ++ (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->next;
            }
            return tmp;
        }
        iterator& operator ++ () {
            if (n) {
                n = n->next;
            }
            return *this;
        }
        iterator operator -- (int) {
            iterator tmp(l,n);
            if (n) {
                n = n->prev;
            }
            return tmp;
        }
        iterator& operator -- () {
            if (n) {
                n = n->prev;
            }
            return *this;
        }
        bool operator != (const iterator& other) const {
            return other.l!=l || other.n!=n;
        }
        bool operator == (const iterator& other) const {
            return other.l==l && other.n==n;
        }
    };

    liste() {
        root = std::allocator<node>().allocate(1, 0);
        root->prev = root->next = root;
    }

    iterator begin() {
        return iterator(this, root->next);
    }

    iterator end() {
        return iterator(this, root);
    }

    void push_front(const T& data) {
        node* n = new node(data);
        n->link(root);
    }

    void push_back(const T& data) {
        node* n = new node(data);
        n->link(root->prev);
    }

    void pop_front() {
        node* n = root->next;
        n->unlink();
        delete n;
    }

    void pop_back() {
        node* n = root->prev;
        n->unlink();
        delete n;
    }
    
    void erase(iterator i)
    {
       iterator current = begin(), ende = end();
        while(current != i && i != ende) ++current;
        
        if(current == ende) //nicht gefunden
        {
            throw std::invalid_argument("Unknown iterator");
        }
        
        current.n->unlink();
        delete current.n;                        
    }    

};

int main() {
       liste<int> list;
       list.push_back(1);
       list.push_back(2);
       list.push_back(3);
      
       //@virtual: DAs geht nicht, wegen den fehlenden typedefs "iterator_category, usw."
       //std::copy(list.begin(), list.end(), std::ostream_iterator<int>(std::cout, " "));
      
       typedef liste<int>::iterator listIter;
       for(listIter i = list.begin(); i != list.end(); ++i)
       {
           std::cout << *i << " ";
       }
      
       list.erase(++list.begin()) ;
       std::cout << '\n';
      
       for(listIter i = list.begin(); i != list.end(); ++i)
       {
           std::cout << *i << " ";
       }
}



jo das friend hab ich schon bemerkt das fehlt. So in der Art hab ichs mir schon gedacht. Danke. Ich hasse templates :P was ich dafür schon an Zeit verbraucht habe, hätte ich die Liste für die 3 Typen einzeln schreiben können
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
019
15.08.2005, 09:00 Uhr
(un)wissender
Niveauwart


Noch schlauer wäre es, std::list zu benutzen.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 < [ 3 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: