Каква е стойността по подразбиране на итератора?

За всеки STL контейнер, който използвам, ако декларирам итератор (от този конкретен тип контейнер), използвайки конструктора по подразбиране на итератора, към какво ще бъде инициализиран итераторът?

Например имам:

std::list<void*> address_list;
std::list<void*>::iterator iter;

С какво ще се инициализира iter?


person The Void    schedule 03.08.2010    source източник
comment
std::list<void*>::iterator iter; е дефиниция. Докато всички дефиниции са декларации, декларация, която не е дефиниция, би била: extern std::list<void*>::iterator iter;.   -  person sbi    schedule 03.08.2010
comment
По-специално, конструкторът принадлежи към дефиницията, а не към друга декларация. Това означава, че можете да предавате стойности на конструктора само в (единичната) дефиниция. Освен това, ако ctor е шаблон (като тук), той се инстанцира там, където е дефиницията.   -  person MSalters    schedule 03.08.2010


Отговори (4)


По конвенция "NULL итератор" за контейнери, който се използва за указване на липса на резултат, се сравнява с резултата от container.end().

 std::vector<X>::iterator iter = std::find(my_vec.begin(), my_vec.end(), x);
 if (iter == my_vec.end()) {
     //no result found; iter points to "nothing"
 }

Въпреки това, тъй като конструиран по подразбиране контейнерен итератор не е свързан с конкретен контейнер, няма добра стойност, която би могъл да приеме. Следователно това е просто неинициализирана променлива и единствената легална операция, която трябва да направите с нея, е да й присвоите валиден итератор.

 std::vector<X>::iterator iter;  //no particular value
 iter = some_vector.begin();  //iter is now usable

За други видове итератори това може да не е вярно. Например в случай на istream_iterator, конструиран по подразбиране итератор представлява (сравнява се с равен) istream_iterator, който е достигнал EOF на входен поток.

person UncleBens    schedule 03.08.2010
comment
Има предложение за съществуване на итератор с инициализирана стойност. Вижте open-std.org/jtc1/sc22 /wg21/docs/papers/2013/n3644.pdf - person Ghita; 29.04.2015
comment
Съгласно това предложение писането на auto ni = vector‹int›::iterator() би създало нулев векторен‹int› итератор, който ще се сравни с всеки друг итератор от същия тип - person Ghita; 29.04.2015
comment
N3644 / null forward итератори съществуват от C++14. Това изглежда е този отговор, но ако разбирам правилно, това е само за итератори напред и по-добре (и само от C++14). - person gast128; 20.07.2020

Конструкторът по подразбиране инициализира итератор към единична стойност:

Итераторите могат също да имат единични стойности, които не са свързани с никоя последователност. [ Пример: След декларацията на неинициализиран указател x (както при int* x;), x винаги трябва да се приема, че има единствена стойност на указател. — краен пример ]
Резултатите от повечето изрази са недефинирани за единични стойности [24.2.1 §5]

person fredoverflow    schedule 03.08.2010
comment
Моето стандартно отвращение отново поразително. <sigh> Какво означава това в разбираема реч? - person sbi; 03.08.2010
comment
@sbi: Абзацът продължава и продължава, реших да го съкратя. По принцип не ви е позволено да правите нищо полезно с единична стойност, например да я дереферирате или да я сравнявате. - person fredoverflow; 03.08.2010
comment
@sbi: просто заменете всички случаи на единствено число със странно. Не ви е позволено да правите нищо с него, защото е в странно състояние. - person jalf; 03.08.2010
comment
@jalf & Fred: Благодаря. интересно Със сигурност никога не съм срещал термина единична стойност. Това означава ли определена специална стойност_ (както NULL е за указатели)? Мислех, че T* е валиден тип за std::vector<T>::iterator? (Старите реализации на Dinkumware правеха това.) Ако това беше вярно, std::vector<T>::iterator it; със сигурност нямаше да инициализира it със специална стойност, докато std::vector<T>::iterator it = std::vector<T>::iterator(); би го направила. - person sbi; 03.08.2010
comment
Може да е полезно да се обмислят единични итератори само за запис, не сочат към последователност (все още). Тъй като те са само за писане, не можете да говорите за стойността, която имат. - person MSalters; 03.08.2010
comment
@sbi: За потребителски дефинирани типове T, дефиницията T x; винаги инициализира x с конструктора по подразбиране (ако има такъв, разбира се). - person fredoverflow; 03.08.2010
comment
@jalf & @Fred: Е, въпросът все още стои. Случайно да знаете отговора? - person sbi; 19.08.2010
comment
@sbi: Не се изисква да има някаква специална стойност, основно е изродено: всъщност не можете да правите нищо с него, освен да му присвоите, за да го приведете в добре дефинирано неединично състояние. Неинициализиран указател би бил пример за единичен итератор. - person jalf; 19.08.2010
comment
@jalf: Благодаря за пояснението. Смятам, че единичната стойност е лошо измислено име за нещо, което може да има всяка възможна стойност. Определено ме отблъсна.... - person sbi; 19.08.2010
comment
Единствената корелация, за която се сещам, е в смисъла на линейната алгебра, напр. сингулярна матрица е тази с безкрайни решения. - person Daniel B.; 17.12.2015

Итераторът не се инициализира, точно както int x; декларира цяло число, което не е инициализирано. Тя няма правилно дефинирана стойност.

person JesperE    schedule 03.08.2010
comment
Има ли начин да инициализирате iter до NULL? - person The Void; 03.08.2010
comment
@The Void: Въпросът ти няма смисъл. NULL е стойност, която указателите могат да имат, итератори на ботове. Докато всички указатели са итератори, не всички итератори са указатели. - person sbi; 03.08.2010
comment
И така, докато има такова нещо като NULL указател, няма такова нещо като NULL итератор? - person The Void; 03.08.2010
comment
@The Void: Итераторът е обект и няма такова нещо като NULL обект. (Да, има този модел, но това е съвсем различно нещо.) Най-близкото нещо до NULL итератор е единствената стойност, описана в моя отговор. - person fredoverflow; 03.08.2010
comment
Няма такова нещо като празен или нулев итератор. Това е същото като ключалката например. Не можете да говорите за празно или нулево заключване, това просто няма смисъл. - person Tomaka17; 03.08.2010
comment
@JesperE: Най-вероятно е инициализирано (итераторите в много случаи са класове и те ще имат конструктор по подразбиране, който инициализира съдържанието). - person David Rodríguez - dribeas; 03.08.2010
comment
@sbi: бот ново съкращение ли е, но не? :) - person codymanix; 04.08.2010
comment
@codymanix: Да, нещо подобно. Предполагам, че мисленето е изпреварило писането и пръстите ми са изневерили, за да наваксат. :) - person sbi; 04.08.2010
comment
@fredoverflow, по ирония на съдбата, някои (всички?) стандартни итератори на контейнери имат конструктор, който приема (изрично?) аргумент nullptr/0, както в std::vector<double>::iterator vit{nullptr}; std::list<double>::iterator lit{nullptr};. Не съм сигурен дали е стандартен (използвам gcc) и каква е целта (може би да приема общ код при инициализацията на указател?). - person alfC; 22.06.2018

Актуализиран отговор.

До и включително C++11: итератор, инициализиран по подразбиране и стойност, може да съдържа единична стойност. Технически може да не се сравнява, нито да се дереферира. Вижте [iterator.requirements.general]/p5.

По конвенция обаче реализациите на STL се използват за инициализиране на такъв итератор като след края итератор.

Започвайки от C++14: итератор forward с инициализирана стойност се сравнява с итератор past-the-end. Вижте [iterators.forward.iterators]/p2 :

... итераторите с инициализирана стойност могат да се сравняват и трябва да се сравняват равни с други итератори с инициализирана стойност от същия тип. [ Забележка: Итераторите с инициализирана стойност се държат така, сякаш препращат след края на същата празна последователност. — крайна бележка ]

Следователно:

std::list<void*>::iterator iter {}; трябва да работи като итератор след края.

std::list<void*>::iterator iter; е опасно, тъй като iter ще бъде инициализирано само ако човек има нетривиален конструктор по подразбиране. Въпреки че за std::list това вероятно ще е така и също трябва да работи.

person rustyx    schedule 28.09.2020
comment
Имайте предвид, че получих противоречиви отговори от: stackoverflow.com/questions/68137196/ - person hl037_; 26.06.2021
comment
@ hl037_ Оставих подобен коментар на свързания отговор; това не противоречи на нищо. Вие обединявате крайния итератор за конкретен контейнер с концепцията за итератор след края. Инициализиран по подразбиране итератор ще се държи като някакъв произволен итератор след края, което означава, че може да бъде дерефериран или сравнен с други от същата последователност (напр. друг инициализиран по подразбиране). Това не го прави скелетен ключ, който се сравнява с всички end() итератори; той е от различен контейнер и сравняването на итератори от различни контейнери не се поддържа. - person Human-Compiler; 26.06.2021