Что случилось с передачей итератора C++ ссылкой?

Я записал несколько функций с прототипом как это:

template <typename input_iterator>
int parse_integer(input_iterator &begin, input_iterator end);

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

std::string sample_text("123 foo bar");
std::string::const_iterator p(sample_text.begin());
std::string::const_iterator end(sample_text.end());
int i = parse_integer(p, end);

Это уехало бы i набор к 123 и p "указание" на пространство прежде foo.

Мне с тех пор сказали (без объяснения), что это - невоспитанность для передачи итератора ссылкой. Это - невоспитанность? Если так, почему?

40
задан squareskittles 23 September 2019 в 14:06
поделиться

6 ответов

В этом нет ничего плохого, но это, безусловно, ограничит использование шаблона. Вы не сможете просто поместить итератор, возвращенный чем-то другим или сгенерированный как v.begin () , поскольку это будут временные. Вам всегда сначала придется делать локальную копию, которая является своего рода шаблоном, который не очень хорошо иметь.

Один из способов - перегрузить его:

int parse_integer(input_iterator begin, input_iterator end, 
                  input_iterator &newbegin);

template<typename input_iterator>
int parse_integer(input_iterator begin, input_iterator end) {
    return parse_integer(begin, end, begin);
} 

Другой вариант - иметь итератор вывода, в который будет записано число:

template<typename input_iterator, typename output_iterator>
input_iterator parse_integer(input_iterator begin, input_iterator end,
                             output_iterator out);

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

int i;
b = parse_integer(b, end, &i);

std::vector<int> numbers;
b = parse_integer(b, end, std::back_inserter(numbers));
32
ответ дан 27 November 2019 в 01:53
поделиться

Когда они говорят «не передавать по ссылке», возможно, это потому, что более нормально / идиоматично передавать итераторы в качестве параметров значения, вместо того, чтобы передавать их по константной ссылке: что вы и сделали, для второй параметр.

Однако в этом примере вам нужно вернуть два значения: проанализированное значение int и новое / измененное значение итератора; и учитывая, что функция не может иметь два кода возврата, кодирование одного из кодов возврата как неконстантной ссылки является нормой IMO.

Альтернативой может быть кодирование его примерно так:

//Comment: the return code is a pair of values, i.e. the parsed int and etc ...
pair<int, input_iterator> parse(input_iterator start, input_iterator end)
{
}
2
ответ дан 27 November 2019 в 01:53
поделиться

На мой взгляд, если вы хотите сделать это, аргумент должен быть указателем на итератор, который вы измените. Я не большой поклонник неконстантных ссылочных аргументов, потому что они скрывают тот факт, что переданный параметр может измениться. Я знаю, что есть много пользователей C ++, которые не согласны с моим мнением по этому поводу - и это нормально.

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

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

template <typename input_iterator>
int parse_integer(input_iterator* begin, input_iterator end);

Теперь вызывающий должен будет делать:

int i = parse_integer(&p, end);

И это ' Будет очевидно, что итератор можно изменить.

Кстати, мне также нравится предложение litb о возврате нового итератора и помещении проанализированных значений в место, указанное итератором вывода.

2
ответ дан 27 November 2019 в 01:53
поделиться

Из perlfaq8:


Как мне добавить каталог, в котором находится моя программа, в путь поиска модуля / библиотеки?

(предоставлено brian d foy)

Если вы уже знаете каталог, вы можете добавить его в @INC, как и любой другой каталог. Вы можете использовать lib, если знаете каталог во время компиляции:

use lib $directory;

Уловка в этой задаче состоит в том, чтобы найти каталог. Прежде чем ваш сценарий сделает что-либо еще (например, chdir), вы можете получить текущий рабочий каталог с помощью модуля Cwd, который поставляется с Perl:

BEGIN {
    use Cwd;
    our $directory = cwd;
    }

use lib $directory;

Вы можете сделать то же самое со значением $ 0, которое содержит имя сценария , Это может содержать относительный путь, но rel2abs может превратить его в абсолютный путь. Если у вас есть

BEGIN {
    use File::Spec::Functions qw(rel2abs);
    use File::Basename qw(dirname);

    my $path   = rel2abs( $0 );
    our $directory = dirname( $path );
    }

use lib $directory;

, модуль FindBin, поставляемый с Perl, может работать. Он находит каталог текущего запущенного скрипта и помещает его в $ Bin,

4
ответ дан 27 November 2019 в 01:53
поделиться

Я думаю, что алгоритмы стандартной библиотеки передают итераторы исключительно по значению (кто-то сейчас опубликует очевидное исключение из этого правила) - это может быть источником идеи. Конечно, ничто не говорит о том, что ваш собственный код должен выглядеть как Стандартная библиотека!

1
ответ дан 27 November 2019 в 01:53
поделиться

Во втором параметре объявления функции отсутствует ссылка, не так ли?

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

Всего одно предложение: внимательно введите параметры.

-1
ответ дан 27 November 2019 в 01:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: