Как передать размер list в итератор?

Рейтинг: 0Ответов: 1Опубликовано: 15.03.2023
#include <iostream>
#include <cstdlib>
#include <limits>
#include <cmath>

namespace s21 {
    template<class T>
    class list {
        public:
            using value_type = T;
            using reference = T&;
            using const_reference = const T&;
            using size_type = std::size_t;
        
        private:
            struct node {
                T value_;
                node *prev;
                node *next;
                node() : value_(), prev(nullptr), next(nullptr) {}
            };
            size_type size_;
            node *first;
            node *last;

        public:
            list(std::initializer_list<T> const &items) : size_(0), first(nullptr), last(nullptr) {
                for (auto it : items) {
                    push_back(it);
                }
            }
            ~list() {
                this->clear();
            }

            void clear() {
                while (size_) {
                    pop_back();
                }
            }

            void push_back(const_reference value) {
                node *tmp = new node;
                tmp->value_ = value;
                if (size_ == 0) {
                    first = tmp;
                    last = tmp;
                } else {
                    tmp->prev = last;
                    last = tmp;
                    tmp->prev->next = tmp;
                }
                size_ = size_ + 1;
                
            }

            void pop_back() {
                    size_--;
                    if (size_ == 0) {
                        delete first;
                        first = nullptr;
                        last = nullptr;
                    } else {
                        node *tmp = last->prev;
                        
                        delete last;
                        last = tmp;
                        last->next = nullptr;
                    }
            }

            public:
                class ListIterator {
                    private: 
                        node *data_;
                        node *first_;
                        node *last_;
                        node *size_;
                        size_type *list_size;
                    public:
                        ListIterator() : data_(nullptr), first_(nullptr), last_(nullptr) {};
                        ~ListIterator() {}
                        ListIterator(node *pointer, list &list) {
                            data_ = pointer;
                            first_ = list.first;
                            last_ = list.last;
                            list_size = &list.size_;
                            size_ = new node;
                            size_->prev = last_;
                            size_->next = first_;
                        }
                        reference operator*() {
                            if (data_ == nullptr) {
                                size_->value_ = *list_size;
                                data_ = size_;
                            }
                            return data_->value_;
                        }
                };
            public:
                using iterator = ListIterator;
                iterator begin() {
                    return iterator(first, *this);
                }
                iterator end() {
                    return iterator(last->next, *this);
                }
    };
}

#include <list>
#include <vector>
#include <iterator>

int main() {
    std::cout<<"Original"<< std::endl;
std::list<int> lister_{4, 5, 6};
  std::list<int>::iterator iterator__(lister_.end());
  std::cout << *iterator__ << std::endl;
  lister_.pop_back();
  lister_.pop_back();
std::cout << *iterator__ << std::endl;


std::cout<<"Custom"<< std::endl;
  s21::list<int> lister{4, 5, 6};
  s21::list<int>::iterator iterator_(lister.end());
  std::cout << *iterator_ << std::endl;
  lister.pop_back();
  lister.pop_back();
std::cout << *iterator_ << std::endl;
  return 0;
}

Из кода много чего ненужного для конкретно этой задачи удалил. Так вот, разыменованный указатель на iterator.end() в оригинале дает размер списка (если это числа). Причем, если из списка удалять элементы, то и возвращаемое разыменованным указателем итератора значение тоже меняется. Но у меня не получается так сделать, возвращается только изначальный размер списка, который был при инициализации итератора. Как сделать, чтобы оно так же менялось при добавлении/удалении элемента в списке?

Ответы

▲ 0

Странная у вас концепция. Вообще-то свойство size - это свойство списка, а не итератора.
Итератор это ссылка на один элемент, он не может вычислять длину списка. Длина списка поддерживается самим списком - либо полем в самом списке (модифицируется при каждом удалении/вставке), либо пересчитывается каждый раз за линейное время.
Не совсем понятен смысл поля размера списка в итераторе - зачем? Да и остальных полей тоже. Если нужно вернуть размер списка итератор просто вызывает соответствующую функцию самого списка.

class ListIterator 
{
private: 
    node *data_;

    node *first_;  // зачем итератору указатель на первый и последний элемент списка? Это свойства списка, а не итератора
    node *last_;  
    node *size_;  // зачем итератору размер? Это свойства списка, а не итератора
    size_type *list_size;

И разыменованный итератор end() не должен давать размер списка. Разыменовывание итератора должно давать ссылку(или копию) значения. А если у вас не числовой тип в списке?
Ваш вариант кода по-сути поддерживает только один итератор для списка. Если вы создадите два итератора - логика рушится.
Запоминая в итераторе свойства списка (начало и конец списка, размер и т.д.) вы делаете снимок состояния списка в момент создания итератора. Но список может меняться независимо от итератора, например другим итератором. Чтобы поддерживать вашу модель, списку нужно хранить ссылки на все созданные итераторы и обновлять их. Это дорого и бессмысленно.
В базовой концепции итератор - это ссылка на один элемент.