Begin c что это
Перейти к содержимому

Begin c что это

Зачем использовать функции begin и end без членов в C++11?

каждый стандартный контейнер имеет begin и end метод возврата итераторов для этого контейнера. Однако C++11, по-видимому, ввел свободные функции под названием std::begin и std::end , которую называют begin и end функции-члены. Итак, вместо того, чтобы писать

в своем выступлении, Написание Современного C++, Херб Саттер говорит, что вы всегда должны использовать бесплатно функции теперь, когда вы хотите итератор начала или конца для контейнера. Однако он не вдается в подробности относительно почему вы хотели бы. Глядя на код, вы спасаете всех от одного символа. Итак, что касается стандартных контейнеров, то свободные функции кажутся совершенно бесполезными. Херб Саттер указал, что существуют преимущества для нестандартных контейнеров, но снова он не стал вдаваться в подробности.

Итак, вопрос в том, что именно делают бесплатные версии функций из std::begin и std::end не вызывайте их соответствующие версии функций-членов, и почему вы хотите их использовать?

6 ответов

Как вы называете .begin() и .end() на C-массива ?

свободные функции позволяют более общее программирование, потому что они могут быть добавлены впоследствии, на структуру данных вы не можете изменить.

рассмотрим случай, когда у вас есть библиотека, которая содержит класс:

он имеет 2 метода:

чтобы перебирать его значения, вам нужно наследовать от этого класса и определить begin() и end() методы для случая, когда

но если вы всегда используете

вы можете сделать это:

здесь SpecialArrayIterator что-то вроде:

теперь i и e может быть легально используется для итерации и доступа к значениям SpecialArray

С помощью begin и end свободные функции добавляют один слой косвенности. Обычно это делается для обеспечения большей гибкости.

в этом случае я могу придумать несколько применений.

наиболее очевидным является использование C-массивов (а не указателей c).

другой — при попытке использовать стандартный алгоритм на несоответствующем контейнере (т. е. в контейнере отсутствует .begin() метод). Предполагая, что вы не можете просто исправить контейнер, следующий лучший вариант-перегрузка the . Herb предлагает вам всегда использовать begin функция для того чтобы повысить единообразие и последовательность в вашем коде. Вместо того, чтобы помнить, какие контейнеры поддерживают метод begin и которым нужна функция begin .

в стороне, следующий c++ rev должен скопировать D’s псевдо-член нотации. Если a.foo(b,c,d) Не определен он вместо этого пытается foo(a,b,c,d) . Это просто немного синтаксического сахара, чтобы помочь нам, бедным людям, которые предпочитают тему глагол заказ.

чтобы ответить на ваш вопрос, свободные функции begin() и end() по умолчанию не делают ничего, кроме вызова члена контейнера .начаться и. конец() функции. От <iterator> , включенный автоматически когда вы используете любой из стандартных контейнеров как <vector> , <list> , etc. вы получаете:

вторая часть вашего вопроса-почему вы предпочитаете свободные функции, если все, что они делают, это вызывать функции-члены в любом случае. Это действительно зависит от того, какой объект v в вашей пример кода. Если тип v является стандартным типом контейнера, например vector<T> v; тогда не имеет значения, используете ли вы функции free или member, они делают то же самое. Если ваш объект v является более общим, как в следующем коде:

затем с помощью функций-членов разбивает код для массивов T = C, строк C, перечислений и т. д. Используя функции, не являющиеся членами, вы рекламируете более общий интерфейс, который люди могут легко расширить. С помощью функции free интерфейс:

код теперь работает с массивами T = C и строками C. Теперь пишем небольшое количество кода адаптера:

мы можем получить ваш код, чтобы быть совместимым с Iterable перечислений тоже. Я думаю, что главная идея Herb заключается в том, что использование свободных функций так же просто, как и использование функций-членов, и это дает вашему коду обратную совместимость с типами последовательностей C и прямую совместимость с типами последовательностей, отличных от STL (и будущих типов stl!), с низкой стоимостью к остальные разработчики.

в то время как функции, не являющиеся членами, не предоставляют никаких преимуществ для стандартных контейнеров, их использование обеспечивает более последовательный и гибкий стиль. Если в какой-то момент Вы хотите расширить существующий класс контейнера, отличный от std, вы бы предпочли определить перегрузки свободных функций вместо изменения определения существующего класса. Поэтому для контейнеров без std они очень полезны, и всегда использование свободных функций делает ваш код более гибким, так как вы можете заменить контейнер std на контейнер без std проще, а базовый тип контейнера более прозрачен для вашего кода, поскольку он поддерживает гораздо более широкий спектр реализаций контейнеров.

но, конечно, это всегда должно быть взвешено должным образом и над абстракцией тоже не хорошо. Хотя использование свободных функций не является чрезмерной абстракцией, оно тем не менее нарушает совместимость с кодом C++03, который в этом молодом возрасте C++11 все еще может быть проблемой для вас.

одно преимущество std::begin и std::end они служат в качестве точек расширения для реализации стандартного интерфейса для внешних классов.

если вы хотите использовать CustomContainer класс с диапазоном на основе цикла или шаблона функция, которая ожидает .begin() и .end() методы, вы, очевидно, должны реализуйте эти методы.

если класс предоставляет эти методы, это не проблема. Когда он не, вам придется изменить его*.

это не всегда возможно, например при использовании внешней библиотеки, особенно коммерческий и закрытый источник один.

в таких ситуациях std::begin и std::end пригодится, так как можно обеспечить iterator API без изменения самого класса, а скорее перегрузка свободных функций.

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

теперь для любого класса, который вы хотели бы использовать с этим custom count_if , у вас есть только чтобы добавить две свободные функции, вместо изменения этих классов.

теперь, C++ имеет mechanisim под названием Аргумент Зависимого Поиска (АДЛ), что делает такой подход еще более гибким.

короче говоря, ADL означает, что когда компилятор разрешает неквалифицированную функцию (i. e. функция без пространства имен, например begin вместо std::begin ), Он также рассмотрим функции, объявленные в пространстве имен ее аргументов. Например:

в этом случае не имеет значения, что квалифицированные имена some_lib::begin и some_lib::end — с CustomContainer находится в some_lib:: кроме того, компилятор будет использовать эти перегрузки в count_if .

это также причина того, что using std::begin; и using std::end; на count_if . Это позволяет использовать неквалифицированных begin и end , поэтому с учетом ADL и разрешение компилятору pick std::begin и std::end когда никакие другие альтернативы не найдены.

мы можем съесть печенье и съесть печенье-И. e. есть способ обеспечить пользовательскую реализацию из begin / end в то время как компилятор может вернуться к стандартным.

по той же причине существуют и другие аналогичные функции: std::rbegin / rend , std::size и std::data .

как упоминают другие ответы, std:: версии имеют перегрузки для голых массивов. Это полезно, но это просто частный случай того, что я описал выше.

используя std::begin и друзья особенно хорошая идея при написании кода шаблона, потому что это делает эти шаблоны более универсальный. Для non-template вы можете просто также используйте методы, когда это применимо.

P. S. Я знаю, что этому посту почти 7 лет. Я наткнулся на него, потому что хотел ответить вопрос, который был отмечен как дубликат и обнаружил, что здесь нет ответа на ADL.

begin — функция

Возвращает итератор, указывающий на начало коллекции, для доступа к которой используется указанный параметр интерфейса.

Синтаксис

Параметры

T
Параметр типа шаблона.

V
Коллекция объектов VectorT или VectorViewT<<>, к которым обращается интерфейс IVectorT<> или IVectorViewT<>.>

i
Коллекция произвольных среда выполнения Windows объектов, к которым обращается интерфейс IIterableT<>.

Возвращаемое значение

Итератор, который указывает на начало коллекции.

Комментарии

Первые две функции шаблона возвращают итераторы, а третья возвращает итератор ввода.

Объект VectorIterator, возвращаемый с начала, — это итератор прокси-сервера, в который хранятся элементы типа VectorProxyT<>. Однако объект прокси-сервера практически никогда не отображается в пользовательском коде. Дополнительные сведения см. в разделе Collections (C++/CX).

Begin c что это

Итераторы обеспечивают доступ к элементам контейнера. С помощью итераторов очень удобно перебирать элементы. Итератор описывается типом iterator . Но для каждого контейнера конкретный тип итератора будет отличаться. Так, итератор для контейнера list<int> представляет тип list<int>::iterator , а итератор контейнера vector<int> представляет тип vector<int>::iterator и так далее.

Для получения итераторов контейнеры в C++ обладают такими функциями, как begin() и end() . Функция begin() возвращает итератор, который указывает на первый элемент контейнера (при наличии в контейнере элементов). Функция end() возвращает итератор, который указывает на следующую позицию после последнего элемента, то есть по сути на конец контейнера. Если контейнер пуст, то итераторы, возвращаемые обоими методами begin и end совпадают. Если итератор begin не равен итератору end, то между ними есть как минимум один элемент.

Обе этих функции возвращают итератор для конкретного типа контейнера:

В данном случае создается вектор — контейнер типа vector, который содержит значения типа int. И этот контейнер инициализируется набором <1, 2, 3, 4>. И через метод begin() можно получить итератор для этого контейнера. Причем этот итератор будет указывать на первый элемент контейнера.

Операции с итераторами

С итераторами можно проводить следующие операции:

*iter : получение элемента, на который указывает итератор

++iter : перемещение итератора вперед для обращения к следующему элементу

—iter : перемещение итератора назад для обращения к предыдущему элементу. Итераторы контейнера forward_list не поддерживают операцию декремента.

iter1 == iter2 : два итератора равны, если они указывают на один и тот же элемент

iter1 != iter2 : два итератора не равны, если они указывают на разные элементы

Например, используем итераторы для перебора элементов вектора:

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

Итераторы позволяют не только получать элементы, но и изменять их:

В данном случае в цикле while элементы вектора возводятся в квадрат. Консольный вывод данной программы:

Константные итераторы

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

Для получения константного итератора также можно использовать функции cbegin() и cend . При этом даже если контейнер не представляет константу, но при этом для его перебора используется константный итератор, то опять же нельзя изменять значения элементов этого контейнера:

Реверсивные итераторы

Реверсивные итераторы позволяют перебирать элементы контейнера в обратном направлении. Для получения реверсивного итератора применяются функции rbegin() и rend() , а сам итератор представляет тип :

Консольный вывод программы:

Если надо обеспечить защиту от изменения значений контейнера, то можно использовать константный реверсивный итератор, который представлен типом const_reverse_iterator и который можно получить с помощью функций crbegin() и crend() :

Также итераторы для всех типов, кроме list и forward_list, поддерживают ряд дополнительных операций:

iter + n : возвращает итератор, который смещен от итератора iter на n позиций вперед

iter — n : возвращает итератор, который смещен от итератора iter на n позиций назад

iter += n : перемещает итератор на n позиций вперед

iter -= n : перемещает итератор на n позиций назад

iter1 — iter2 : возвращает количество позиций между итераторами iter1 и iter2

>, >=, <, <= : операции сравнения. Один итератор больше другого, если указывает на элемент, который ближе к концу

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *