Интересно почему cbegin
и cend
были введены в C ++ 11?
В каких случаях вызов этих методов отличается от константных перегрузок begin
и end
?
Интересно почему cbegin
и cend
были введены в C ++ 11?
В каких случаях вызов этих методов отличается от константных перегрузок begin
и end
?
Это довольно просто. Скажем, у меня есть вектор:
std::vector<int> vec;
Я заполняю его некоторыми данными. Тогда я хочу получить несколько итераторов. Может быть, передать их. Может быть std::for_each
:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
В C ++ 03 можно SomeFunctor
было свободно изменять параметр, который он получает. Конечно, SomeFunctor
может принимать его параметр по значению или по const&
, но нет способа гарантировать, что он делает. Не без глупостей:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
Теперь мы представляем cbegin/cend
:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
Теперь у нас есть синтаксические гарантии, которые SomeFunctor
не могут изменить элементы вектора (конечно, без преобразования). Мы явно получаем const_iterator
s, и поэтому SomeFunctor::operator()
будем вызывать с const int &
. Если он принимает параметры как int &
, C ++ выдаст ошибку компилятора.
C ++ 17 имеет более элегантное решение этой проблемы: std::as_const
. Ну, по крайней мере, это элегантно при использовании диапазона for
:
for(auto &item : std::as_const(vec))
Это просто возвращает const&
объект, который он предоставляет.
std::cbegin/cend
свободных функций, которыеstd::begin/std::end
существуют. Это был недосмотр комитета. Если бы эти функции существовали, это был бы способ их использования.std::cbegin/cend
будет добавлено в C ++ 14. См. En.cppreference.com/w/cpp/iterator/beginfor(auto &item : std::as_const(vec))
эквивалентноfor(const auto &item : vec)
?const
ссылку. Ник рассматривает контейнер как const, поэтомуauto
выводитconst
ссылку. ИМОauto const& item
проще и понятнее. Непонятно, почемуstd::as_const()
здесь хорошо; Я вижу, что это было бы полезно при передаче чего-то неconst
общего кода, где мы не можем контролировать используемый тип, но с помощью range-for
мы можем, так что это просто кажется мне дополнительным шумом.Помимо того, что Никол Болас сказал в своем ответе , рассмотрим новое
auto
ключевое слово:С
auto
, нет никакого способа убедиться, чтоbegin()
возвращает константный оператор для неконстантной ссылки на контейнер. Итак, теперь вы делаете:источник
const_iterator
это просто еще один идентификатор. Ни одна из версий не использует поиск обычных членов typedefsdecltype(container)::iterator
илиdecltype(container)::const_iterator
.const_iterator
сauto
: Напишите шаблон вспомогательной функции, вызываемойmake_const
для определения аргумента объекта.Возьмите это в качестве практического использования
Назначение не выполняется, потому что
it
это неконстантный итератор. Если бы вы использовали cbegin изначально, итератор имел бы правильный тип.источник
С http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
Они привели этот пример
Обратите внимание , что рабочий документ , также упоминается адаптер шаблонов, которые теперь были завершены , как
std::begin()
иstd::end()
и , которые также работают с носителями массивов. Соответствующиеstd::cbegin()
и,std::cend()
как ни странно, отсутствуют на этот раз, но они также могут быть добавлены.источник
Просто наткнулся на этот вопрос ... Я знаю, что он уже ответил, и это просто боковой узел ...
auto const it = container.begin()
это другой тип, тоauto it = container.cbegin()
разница для
int[5]
(используя указатель, который, я знаю, не имеет метода begin, но хорошо показывает разницу ... но будет работать в c ++ 14 дляstd::cbegin()
иstd::cend()
, что по сути то, что следует использовать, когда он здесь) ...источник
iterator
иconst_iterator
имеют отношения наследования, и неявное преобразование происходит по сравнению с другим типом или присваивается ему.Использование
cbegin()
иcend()
увеличит производительность в этом случае.источник
const
главное преимущество - это производительность (а это не так: это семантически правильный и безопасный код). Но, хотя у вас есть точка зрения, (А)auto
делает это не проблема; (B) говоря о производительности, вы упустили главное, что вы должны были здесь сделать: кэшироватьend
итератор, объявив его копию в init-условииfor
цикла, и сравнить с этим, вместо того, чтобы получать новую копию с помощью значение для каждой итерации. Это сделает вашу точку зрения лучше. : Pconst
определенно может помочь достичь более высокой производительности не из-за некоторого волшебства в самомconst
ключевом слове, а потому, что компилятор может включить некоторые оптимизации, если он знает, что данные не будут изменены, что было бы невозможно в противном случае. Проверьте этот бит из выступления Джейсона Тернера для живого примера этого.const
может (почти косвенно) привести к повышению производительности; на тот случай, если кто-то прочитает это, возможно, подумает: «Я не буду беспокоиться о добавлении,const
если сгенерированный код никогда не будет затронут», что неверно.это просто, cbegin возвращает постоянный итератор, где begin возвращает просто итератор
для лучшего понимания давайте рассмотрим два сценария
сценарий - 1:
это будет работать, потому что здесь итератор i не является константой и может быть увеличен на 5
Теперь давайте используем cbegin и обозначаем их как сценарий с постоянными итераторами - 2:
это не сработает, потому что вы не можете обновить значение, используя cbegin и cend, которые возвращают постоянный итератор
источник