Нужно внутри функции получить доступ к элементам контейнера только на чтение. Как более правильно (эффективнее) это сделать?
В каких случаях следует использовать передачу ссылки на контейнер (как в f1), а в каких случаях итераторы (как в f2, почему-то в stl именно так):
void f1(const std::vector<int> & x){
// ... used all elements of x
}
void f2(const std::vector<int>::const_iterator beg,const std::vector<int>::const_iterator end){
// ... used all elements
}
// ...
std::vector<int> y = {1,2,3};
f1(y);
f2(y.begin(),y.end());
_>В каких случаях следует использовать передачу ссылки на контейнер (как в f1), а в каких случаях итераторы (как в f2, почему-то в stl именно так): _>
_>void f1(const std::vector<int> & x){
_> // ... used all elements of x
_>}
_>void f2(const std::vector<int>::const_iterator beg,const std::vector<int>::const_iterator end){
_> // ... used all elements
_>}
_>// ...
_>std::vector<int> y = {1,2,3};
_>f1(y);
_>f2(y.begin(),y.end());
_>
Второй способ более универсальный.
И совпадает с STL — привычно программисту. А значит — меньше случайных опечаток-ошибок.
И похоже, что в вашем случае просто можно подходящий стандартный алгоритм использовать (вместо писания своей функции)?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, sci_reseacher, Вы писали:
_>Нужно внутри функции получить доступ к элементам контейнера только на чтение. Как более правильно (эффективнее) это сделать?
Воспользуйся здравым смыслом:
Если ты решаешь, какие эл-ты контейнера обработать внутри функции, то передавай константную ссылку на контейнер, если вне — то константные итераторы.
_>В каких случаях следует использовать передачу ссылки на контейнер (как в f1), а в каких случаях итераторы (как в f2, почему-то в stl именно так):
Алгоритмы stl работают с кусочками контейнера, определенными пользователем, поэтому в них передаются итераторы.
Здравствуйте, sci_reseacher, Вы писали: _>Нужно внутри функции получить доступ к элементам контейнера только на чтение. Как более правильно (эффективнее) это сделать?
На самом деле это два разных вопроса. _>Как более правильно это сделать?
Правильно — это таким способом, чтобы ваши коллеги могли прочитать, что вы написали. _>Как более (эффективнее) это сделать?
С помощью итераторов — они самые быстрые. _>В каких случаях следует использовать передачу ссылки на контейнер (как в f1),
Передачу ссылки следует использовать когда требуется непоследовательный доступ к элементам или же для облегчения чтения (экономии кода):
_>а в каких случаях итераторы (как в f2, почему-то в stl именно так):
В стандартной библиотеке не так как в f2. В стандартной библиотеке используются шаблоны, что позволяет подставлять различные итераторы, например reverse_iterator'ы, которые можно использовать для доступа к элементам в обратном порядке.
Еще важно то, что при использовании итераторов возможно прохождение не по всем элементам контейнера, например:
f2(y.begin() + 1, y.end());
Скрытый текст
_>
_>void f1(const std::vector<int> & x){
_> // ... used all elements of x
_>}
_>void f2(const std::vector<int>::const_iterator beg,const std::vector<int>::const_iterator end){
_> // ... used all elements
_>}
_>// ...
_>std::vector<int> y = {1,2,3};
_>f1(y);
_>f2(y.begin(),y.end());
_>
Код эффективнее не станет от того, что ты вызовешь begin и end вне тела функции, а не внутри.
А в некоторых случаях передача контейнера может быть предпочтительнее: если у контейнера константный и неконстантный begin/end отличаются по устройству (например, из-за использования copy-on-write), то может быть выгоднее сначала навесить на контейнер const, а потом вызвать константный метод begin, чем сначала вызвать неконстантный begin, а потому полученный итератор преобразовывать в const_iterator. Впрочем такие случаи достаточно редки, и уж std::vector к ним, конечно, не относится.
_> Как более правильно (эффективнее) это сделать?
Зачем выбирать только один способ? Напиши два метода с одним именем:
Если у пользователя есть контейнер, то незачем его заставлять писать вспомогательные вызовы begin/end, если запись process(container) выглядит и короче, и понятнее.
А если возникнет всё же необходимость, то всегда можно вызвать более общую функцию: process(lower_bound(foo), upper_bound(bar)) или что там ещё понадобится.
_> почему-то в stl именно так
Это чтобы была возможность применить алгоритм только к части контейнера.
Здравствуйте, sci_reseacher, Вы писали:
_>В каких случаях следует использовать передачу ссылки на контейнер (как в f1), а в каких случаях итераторы (как в f2, почему-то в stl именно так):
Она позволит использовать оба способа.
(Способ с итераторами более универсален, но дает менее читаемый код. "Range" позволяет не выбирать между способами).
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: как передавать элементы контейнера в функцию
Здравствуйте, watchmaker, Вы писали:
W>А в некоторых случаях передача контейнера может быть предпочтительнее: если у контейнера константный и неконстантный begin/end отличаются по устройству (например, из-за использования copy-on-write), то может быть выгоднее сначала навесить на контейнер const, а потом вызвать константный метод begin, чем сначала вызвать неконстантный begin, а потому полученный итератор преобразовывать в const_iterator.
Здравствуйте, sci_reseacher, Вы писали: _>Нужно внутри функции получить доступ к элементам контейнера только на чтение. Как более правильно (эффективнее) это сделать? _>В каких случаях следует использовать передачу ссылки на контейнер (как в f1), а в каких случаях итераторы (как в f2, почему-то в stl именно так):
<ccode>
_>
_>void f1(const std::vector<int> & x){
_> // ... used all elements of x
_>}
_>void f2(const std::vector<int>::const_iterator beg,const std::vector<int>::const_iterator end){
_> // ... used all elements
_>}
_>// ...
_>std::vector<int> y = {1,2,3};
_>f1(y);
_>f2(y.begin(),y.end());
_>
using boost::iterator_range;
using std::vector;
void f3(iterator_range<vector<int>::const_iterator> range){
for (auto value : range)
{
// use of elements of the range
}
}
// ...
std::vector<int> y = {1,2,3};
f3(y);
f3(boost::make_iterator_range(boost::next(y.begin()), boost::prior(y.end())));
--
Справедливость выше закона. А человечность выше справедливости.