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 ]
000
08.08.2005, 23:08 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


Hi, hab folgende probleme:

1. manchmal krieg ich access violations (it.it ist dann seltsamerweise null)
2. krieg ich das nicht mim gcc kompiliert (it undefined, bezogen auf Zeilen mit liste<T>::iterator it)


C++:
#ifndef LISTE_H_
#define LISTE_H_

template <class T>
class liste
{
public:
    class item
    {
    public:
        item *next, *prev;
        T data;
    };

    class iterator
    {
        item * it;

    public:
        friend class liste;

        iterator() { it = NULL; }
        iterator(item * it) { this->it = it; }

        iterator operator++() { return (it = it->next); }
        iterator operator--() { return (it = it->prev); }

        T& operator *() { return it->data; }
        T * operator->() { return &it->data; }

    bool not_end()   { return (it ? (it->next ? true : false) : false); }
    bool not_begin() { return (it ? (it->prev ? true : false) : false); }
    };

private:

    item head;
    item tail;
    unsigned count;

public:

    liste();
    ~liste() { clear(); }

  void init();

    unsigned elements() { return count; }
    void clear();

    iterator first(){ return head.next;}
    iterator last() { return tail.prev;}

    void insert(const iterator it,const T& data);
    void erase(const iterator it);

    void push_front(const T& data)
  {
    iterator it = &head;
    if(it.it == NULL)
    {
      init();
      it.it = &head;
    }
    insert(it,data);
  }
    void push_back(const T& data)
  {
    iterator it = tail.prev;
    if(it.it == NULL)
    {
      init();
      it.it = tail.prev;
    }
    insert(it,data);
  }

    bool search(const T& data);
};


template <class T>
liste<T>::liste()
{
  init();
}

template <class T>
void liste<T>::init()
{
    head.prev = NULL;
    head.next = &tail;

    tail.prev = &head;
    tail.next = NULL;

    count = 0;
}

template <class T>
void liste<T>::clear()
{
    if(!count)
        return;

    liste<T>::iterator it = this->first();

    for(unsigned i = 0;i<count;++i)
    {
        ++it;
        delete it.it->prev;
    }

    count = 0;
}


template <class T>
void liste<T>::insert(const iterator it,const T& data)
{
    item * tmp = it.it->next;
    it.it->next = new liste<T>::item;
    it.it->next->data = data;
    it.it->next->next = tmp;
    it.it->next->prev = it.it;
    tmp->prev = it.it->next;

    ++count;
}

template <class T>
void liste<T>::erase(const iterator it)
{
    item * prev = it.it->prev;
    item * next = it.it->next;

    delete it.it;

    prev->next = next;
    next->prev = prev;

    --count;
}

template <class T>
bool liste<T>::search(const T& data)
{
    for(iterator it = first();it.not_end();++it)
        if(*it == data)
            return 1;
    return 0;
}

#endif // !LISTE_H_



Ich weiß nicht, evtl kann das ja einer durchschaun der mehr ahnung von templates usw hat, thx
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
09.08.2005, 07:08 Uhr
(un)wissender
Niveauwart


Schreib mal typename davor.
Ansonsten gibt mal einen Main mit, wo dann it null wird.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
09.08.2005, 08:34 Uhr
virtual
Sexiest Bit alive
(Operator)


@Flosoft
ich habe es nicht im Detailbetrahtet, aber Bauchschmerzen würde mir das hier bereiten:

C++:
    item head;
    item tail;


Ist es nicht so, daß du bei einfüge/löschoperationen gleich ne ganze Menge mitpflegen musst? - Und warum nicht einfach:

C++:
    item head;


Weshalb hälst Du redundanzen? - Du machst deine List-Klasse um einen nennenswerten Anteil größer, ohne daß Du davon einen Vorteil haben würdest.
--
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
003
09.08.2005, 09:06 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


du meinst, den "hintern" kann ich mir sparen?

ansonsten @(un)wissender: wo meinst du?

Ansonsten hab ich diverse klassen, z.b so:

C++:
class XY
{
  public:
     CElement elements[10];
};

class CItem
{
};

class CElement
{
public:
  liste<CItem*> items;
};



und wenn ich eben von CElement was hinzufüge z.b so:


C++:
XY *xy = new XY;

xy->elements[1].items.push_back(item);



dann stürzt er in der push_back-Zeile ab, bzw an dieser Stelle:


C++:
void liste<T>::insert(const iterator it,const T& data)
{
    item * tmp = it.it->next; // <-- it.it == NULL



ich hab dann push_back geändert das sich das wieder initialisiert:


C++:
   void push_back(const T& data)
  {
    iterator it = tail.prev;
    if(it.it == NULL) // <-- hier
    {
      init();
      it.it = tail.prev;
    }
    insert(it,data);



dann geht es, nur irgendwo ist das nicht das wahre?

Ansonsten wie gesagt, krieg ich folgende gcc-Fehler:


C++:
liste.h:106: Fehler: expected `;' vor "it"
liste.h:110: Fehler: `it'
undeclared (first use this function)
liste.h:110: Fehler: (Each undeclared identifier is reported only once for each function it appears in.)
liste.h: In member function `void liste<T>::insert(liste<T>::iterator, const T&)':
liste.h:122: Fehler: `class liste<T>::item'
is not a type



Zeile 106 und 110 bezieht sich auf:


C++:
void liste<T>::clear()
{
    if(!count)
        return;

    liste<T>::iterator it = this->first(); // <-- 106

    for(unsigned i = 0;i<count;++i)
    {
        ++it; // <-- 110



Zeile 122:


C++:
void liste<T>::insert(const iterator it,const T& data)
{
    item * tmp = it.it->next;
    it.it->next = new liste<T>::item; // <-- 122



versteh nur nicht wieso?
--
class God : public ChuckNorris { };

Dieser Post wurde am 09.08.2005 um 10:36 Uhr von Pablo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
09.08.2005, 09:18 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von FloSoft:
du meinst, den "hintern" kann ich mir sparen?


Ja, mehr noch: Deine Implementierung ist recht problematisch:

C++:
template<typename T>
class liste
{
public:
    class item
    {
    public:
        item *next, *prev;
        T data;
    };
    ...
private:

    item head;
    item tail;
    ...
};


Bedeutet, daß Deine Liste mindestens zwei Ts enthält - eines steht eben in head, ein anderes eben in tail. Wie erzeugst Du eine Leere Liste? - Vermutlich dadurch, daß Du irgendwie die Ts in head und tail ignorierst... Aber die sind ja nun mal trotzdem da! IMHO richtiger wäre:

C++:
template<typename T>
class liste
{
private: // Niemanden geht eigentlich an, wie item aussieht. Daher private
    class item
    {
    public:
        item *next, *prev;
        T data;
    };
    ...
private:

    item* head; // nur ein Zeiger
    ...



Du wirst so oder so nicht darum herum kommen, head bei einfüge/entfernen Operationen mit zu pflegen.
--
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
005
09.08.2005, 10:51 Uhr
Th



Wenn man eine doppelt verkettete List erzeugen will, von der man auch rückwärts suchen will, so macht "tail" schon Sinn, aber wie "virtual" geschriebn hat, muß das bei jedem 'insert' und 'erase' mitgepflegt werden.

Zu den Fehlern, so wie "(un)wissender" geschrieben hat, mittels typename:

C++:
typename liste<T>::iterator it = this->first();

new typename liste<T>::item;


sonst weiß der Compiler nicht, daß iterator bzw. item ein Typ ist, sondern denkt, dies wäre ein Member.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
09.08.2005, 12:51 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


@Th: jo hab ich schon rausgefunden, der VC braucht das nicht, gcc schon, egal

hab nun mal die klasse umgebaut:


C++:
#ifndef LISTE_H_
#define LISTE_H_

template <class T>
class liste
{
private:
  class item
  {
  public:
    item() { next = NULL; prev = NULL; }
    item *next, *prev;
    T data;
  };

  item *root;
  unsigned int count;

public:
  class iterator
  {
    friend class liste;

    item *it;

  public:
    iterator() { it = NULL; }
    iterator(item * it) { this->it = it; }

    iterator operator++() { return (it = it->next); }
    iterator operator--() { return (it = it->prev); }

    T& operator *() { return it->data; }
    T * operator->() { return &it->data; }

    bool not_end()
    {
      return (it ? true : false);
    }
    bool not_begin()
    {
      return (it ? true : false);
    }
  };

  liste();
  ~liste();

  void init();
  void clear();

  unsigned int size();

  void push_back(const T& data);
  void push_front(const T& data);

  //void insert(const iterator it, const T& data);
  void erase(const iterator it);

  bool search(const T& data);

  iterator begin()
  {
    return root;
  }

  iterator end()
  {
    item *current = root;
    while(current)
    {
      if(current->next)
        current = current->next;
      else
        return current;
    }
    return root;
  }
};


template <class T>
liste<T>::liste()
{
  count = 0;
  root = NULL;
  init();
}

template <class T>
liste<T>::~liste()
{
  clear();
}

template <class T>
void liste<T>::init()
{
  clear();
}

template <class T>
void liste<T>::clear()
{
  if(!count)
    return;

  count = 0;

  item *current = root;
  while(current)
  {
    if(current->next)
      current = current->next;
    else
    {
      current = current->prev;
      if(current)
      {
        delete current->next;
        current->next = NULL;
      }
    }
  }
  delete root;
  root = NULL;
}

template <class T>
unsigned int liste<T>::size()
{
  return count;
}

template <class T>
void liste<T>::push_back(const T& data)
{
  if(root)
  {
    item *current = root;
    item *neu = new item;

    neu->next = NULL;
    neu->prev = NULL;
    neu->data = data;

    while(current)
    {
      if(current->next)
        current = current->next;
      else
      {
        current->next = neu;
        neu->prev = current;
        break;
      }
    }
  }
  else
  {
    root = new item;
    root->data = data;
    root->next = NULL;
    root->prev = NULL;
  }

  count++;
}

template <class T>
void liste<T>::push_front(const T& data)
{
  if(root)
  {
    item *current = root;
    item *neu = new item;

    neu->next = root;
    neu->prev = NULL;
    neu->data = data;

    root->prev = neu;

    root = neu;
  }
  else
  {
    root = new item;
    root->data = data;
    root->next = NULL;
    root->prev = NULL;
  }

  count++;
}

template <class T>
void liste<T>::erase(const iterator it)
{
  item * prev = it.it->prev;
  item * next = it.it->next;

  delete it.it;

  prev->next = next;
  next->prev = prev;

  --count;
}

template <class T>
bool liste<T>::search(const T& data)
{
  for(iterator it = first(); it.not_end(); ++it)
    if(*it == data)
      return 1;
  return 0;
}

#endif // !LISTE_H_



Nur krieg ich immer

"Zugriffsverletzung-Leseposition 0xbaadf005"

bei z.b so was:


C++:
  for(liste<CCtrl*>::iterator it = m_pControls.begin();it.not_end();++it)
    delete (*it);



da begin ja nen "Null-iterator" liefert.

Man für die zeit die für das template draufgeht hätt ich die klasse einmal schreiben und 3x kopieren können
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
09.08.2005, 13:08 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


lol ich bin ein trottel, die av's kamen von was anderem, naja egal, gibts evtl noch verbesserungen zu dem template?
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
10.08.2005, 15:24 Uhr
Oliver
S2-Pixelgeneral



Zitat von virtual:


C++:
template<typename T>
class liste
{
private: // Niemanden geht eigentlich an, wie item aussieht. Daher private
    class item
    {
    public:
        item *next, *prev;
        T data;
    };
    ...
private:

    item* head; // nur ein Zeiger
    ...



Du wirst so oder so nicht darum herum kommen, head bei einfüge/entfernen Operationen mit zu pflegen.



Bloß wie willst du dann push_back(...) implementieren?
--
Demokratie ist die Diktatur der Mehrheit.

www.siedler25.org/ ( Siedler2 - Remake )
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
10.08.2005, 16:25 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von Oliver:


Bloß wie willst du dann push_back(...) implementieren?



Ich glaube, ich würde die Verlinkung der Listenelement anders machen, als in diesem Thread angedacht. Flosoft würde bei head den Vorgänger auf NULL setzen und bei seinem tail eben den nachfolger auch. Das würde ich nicht machen. Ich würde head auf den vorgänger zeigen lassen, so daß head->prev immer auf das letzte Element in der Liste zeigt und tail->next immer auf das erste (wobei ich tail natürlich nicht als listen attribute brauche).

Damit werden alle Operationen etwas einfacherer und es wird platz gespart; lediglich beim Iterator muß man eine kleine Änderung vornehmen.

Im falle einer einfach verketteten Liste würde ich natürlich nicht head sondern tail in der Klasse lassen, aber dennoch diese Ring-verlinkung machen.

Übrigens lann man mit ein paar Kniffen sogar darum herum kommen, immer diesen head-Pointer nachhalten zu müssen (Mit den STL Allocatoren geht das).
--
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
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: