2016-11-21 3 views
2

Следующий код печатает числа от 0 до 9 с пользовательскими итераторами. Я компилирую с g++ -std=c++11 -o test test.cppC++ custom iterator constructor

#include <iostream> 

class some_class; 

class some_class_iterator : public std::iterator<std::forward_iterator_tag, int>{ private:  
    friend class some_class; 
    int pointed; 
    some_class_iterator(int _pointed): pointed(_pointed){ 
     std::cout << "over here" << std::endl; 
    } 

public: 
    int poitned; 

    int operator*(){ 
     return pointed; 
    } 

    const some_class_iterator& operator++(){ 
     pointed++; 
     return *this; 
    } 

    bool operator!=(const some_class_iterator& other) const { 
     return this->pointed != other.pointed; 
    } 

}; 

class some_class{ 
public: 
    typedef some_class_iterator iterator; 

    iterator begin(){ 
     return some_class_iterator(0); 
    } 

    iterator end(){ 
     return some_class_iterator(10); 
    } 

}; 


int main(){ 

    some_class a; 
    for (some_class::iterator i = a.begin(); i != a.end(); ++i) std::cout << *i << std::endl; 

} 

Однако выход не то, что я ожидал, чтобы быть over here напечатан несколько раз. Например фактический выход:

over here 
over here 
0 
over here 
1 
over here 
2 
over here 
3 
over here 
4 
over here 
5 
over here 
6 
over here 
7 
over here 
8 
over here 
9 
over here 

Так кто вызывает вызов конструктора здесь?

Моя фактическая проблема заключается в итераторе дерева бинарного поиска, где в конструкторе я создаю обход FIFO с печатаемыми узлами в зависимости от (in, pre, post), поэтому вызов конструктора несколько раз является дорогостоящим.

ответ

3

На каждой итерации цикла вы вызываете a.end(), что создаст новый итератор и напечатает «здесь». Вы можете распечатать значение _pointed, чтобы увидеть это. (Первый «здесь» от звонка begin).

+0

* High five! * ... и некоторый текст наполнителя. –

+0

К сожалению, это был вопрос с ошибкой ... –

+1

@k_kaz Нет, у вас есть некоторое вдохновение для будущих методов отладки, поэтому в конце концов это своего рода победа. –

1

Каждый раз, когда вы проверяете условие в цикле for, вы вызываете end(), который создает новый итератор.

Если вы добавили point_ в свой вывод отладки, это может помочь проследить подобные вещи. Таким образом, вы можете добавлять распечатки к своим другим вызовам, а также переходить в отладчик.

Чтобы избежать этого, вы можете кэшировать конец перед циклом for, но это странно и не подходит для обычного шаблона для циклирования с помощью итераторов. Лучшее решение может состоять в том, чтобы хранить конец как член в вашем классе и иметь end() вернуть ссылку на него или посмотреть, можно ли найти способ сделать конструкцию итератора менее дорогостоящей в вашей реальной программе.

+0

Если some_class :: end() вернул эту ссылку на const, о которой вы говорите, это лучший дизайн? –

+0

@k_kaz Да, это было бы неплохо. –