Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > [?] Организация циклического списка


Автор: XuTMAH 3.10.2005, 21:05
Есть следующая идея:
Код

class A : public list< T >::iterator
{
    public:
    A();
    A(list< T >::iterator iter) : list< T >::iterator(iter){}
    ~A();    
    A operator++(int);
    A& operator++();
    A operator--(int);
    A& operator--();
};
class B : list< T >
{
    private:
    
    A begin_iterator;
    
    public:
    B() : list< T >(const1), 
    begin_iterator( (*(base*)this).begin() ){};
    ~B();
    A begin() { return begin_iterator; }
};


Но есть некоторые проблемы, а именно:
1) Нужно чтобы, например, в операции ++ осуществлялось следующее: когда итератор становиться законечным (т.е. возвращамым функцией list< T >::end() ) нужно чтобы он сразу становился первым (т.е. например сделать ещё один ++ и он станет первым), тогда возникает вопрос - как узнать из самого итератора, что он законечный? возможен вариан воспользоваться try-catch но опять же вопрос - какая операция для законечного итератора может сгенерировать исключение?
Может какие-нибудь ещё способы есть узнать, что итератор законечный?
2) Нужно сохранять итератор псевдо начала этого циклического списка, т.к. "начало" у него будет потихоньку перемещаться и не один раз пройдёт через обычное начало, но представленый мной вариан не работает, даже не знаю почему.

P.S. Очень не хочется заморачиваться с new/delete и надеюсь STL спасёт меня...

Заранее благодарю за помощь.

Автор: Earnest 3.10.2005, 21:37
Цитата(XuTMAH @ 3.10.2005, 21:05)
как узнать из самого итератора, что он законечный? возможен вариан воспользоваться try-catch но опять же вопрос - какая операция для законечного итератора может сгенерировать исключение?

Никак не узнать. Реализации list::iterator могут быть разными, но чаще всего он просто хранит указатель на узел списка.
Исключения при обращении к невалидному итератору могут возникнуть, а могут и нет (смотря куда нарвешься). И вообще, это не способ: генерировать исключение, чтобы что-нибудь узнать - крайне неправильно: это очень накладно!
Cпособ один: хранить в твоем циклическом итераторе начальный и конечный итераторы исходного списка.
Ты бы сформулировал задачу поточнее, а то возникает вопрос: через конец-то ты пройдешь, а заканчивать итерирование ты как будешь? Если list::end() никогда не будет возвращаться?

Автор: XuTMAH 4.10.2005, 14:55
Цитата(Earnest @ 3.10.2005, 21:37)
Ты бы сформулировал задачу поточнее, а то возникает вопрос: через конец-то ты пройдешь, а заканчивать итерирование ты как будешь? Если list::end() никогда не будет возвращаться?


Заканчивать буду по равенству с псевдо началом => нужно будет оператор == перегрузить.


Немного доработав и дополнив код:

Код

#include <list>

using namespace std;

class A : public list< int >::iterator
{
    private:
    typedef list< int >::iterator base;
    base end_iterator;
    public:
    A();
    A(base iter, base end_iter) : base(iter), end_iterator(end_iter) {}
    ~A(){}    
    A operator++(int);
    A& operator++(){ ++(*(base*)this); return *this; }
    A operator--(int);
    A& operator--();
    bool operator==(A other);
};
class B : public list< int >
{
    private:
    typedef list< int > base;
    
    A begin_iterator;
    
    public:
    B();
    B(int param) : list< int >(2), 
    begin_iterator( (*(base*)this).begin(), (*(base*)this).end() )
    {
    //use param
    }
    ~B(){}
    A begin() { return begin_iterator; }
};
class C
{
    public:
    list< B > C_member;
    C() : C_member(1, B(222) ) {} ///Корректен ли такой вызов конструктора list<B> ???
    ~C(){}
};
void main()
{
    C cc;
    list< B >::iterator    bb( cc.C_member.begin() );
    A aa( (*bb).begin() );    

//    B bb(222);
//    A aa( bb.begin() ); 

    ++aa;
    ++aa;
    ++aa;
    ++aa;
    ++aa;
}



Возникла более конкретная проблема, а именно:
почему не правильно работает вариант написанный в main() (закоментированый - рабочий), т.е. при вызове конструктора "C" некорректно конструируется класс "B" (это можно проверить по непонятному значению поля B.begin_iterator) ???

Автор: Guest 5.10.2005, 02:32
Ошибка в конструкторе:
Цитата
   begin_iterator( (*(base*)this).begin(), (*(base*)this).end() )
    {
    //use param
    }

Лично у меня компилятор выдал предупреждение:
warning C4355: 'this' : used in base member initializer list
В MSDN'е на этот счет написано:
Цитата

The this pointer is valid only within nonstatic member functions. It cannot be used in the initializer list for a base class.

The base-class constructors and class member constructors are called before this constructor. In effect, you've passed a pointer to an unconstructed object to another constructor. If those other constructors access any members or call member functions on this, the result will be undefined. You should using the this pointer until all construction has completed.

Если в кратце, то нельзя использовать this в конструкторах.

Автор: XuTMAH 5.10.2005, 12:00
Наверное не зря компилятор ругается...
Но почему же тогда если заменить следующий кусок кода в main()
Код

    C cc;
    list< B >::iterator    bb( cc.C_member.begin() );
    A aa( (*bb).begin() );    
//    B bb(222);
//    A aa( bb.begin() ); 


на

Код

//    C cc;
//    list< B >::iterator    bb( cc.C_member.begin() );
//    A aa( (*bb).begin() );    
    B bb(222);
    A aa( bb.begin() ); 


то всё работает без единой ошибочки, хотя
Код

    begin_iterator( (*(base*)this).begin(), (*(base*)this).end() )
    {
    //use param
    }


этот конструктор всё равно вызывается ...

Как инересно правильно написать?
Если так
Код

    begin_iterator( base::begin(), base::end() )
    {
    //use param
    }


то результат ни в одном ни в другом случае не изменяется...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)