Объединение в цепочку итераторов для C++

Значение в BackgroundWorker заключается в том, что он может вызывать свои события ProgressChanged и RunworkerCompleted в потоке, создавшем его экземпляр. Что делает его очень удобным в программах, которые не поддерживают свободную многопоточность.

Для того, чтобы это работало должным образом, необходимо, чтобы свойство SynchronizationContext.Current ссылалось на провайдера синхронизации не по умолчанию. Поставщик, который отвечает за маршалинг вызовов из одного потока в другой. .NET Framework имеет два доступных поставщика: System.Windows.Forms.WindowsFormsSynchronizationContext и System.Windows.Threading.DispatcherSynchronizationContext. Эти провайдеры обрабатывают синхронизацию соответственно для Winforms и WPF.

Существует соединение, Winforms и WPF являются библиотеками классов, в которых есть проблема с многопоточностью. Оба реализуют графические интерфейсы пользователя и графические пользовательские интерфейсы на основе Windows, в основном поточно-ориентированные. Окна Windows могут быть обновлены только из потока, который их создал. Другими словами, эти пользовательские поставщики синхронизации существуют, потому что они крайне необходимы. Также следует отметить, что они работают, используя преимущества работы потоков пользовательского интерфейса. Поток пользовательского интерфейса выполняет код, управляемый событиями, прокачивая цикл сообщений для получения уведомлений. Поставщик синхронизации может внедрять вызовы в обработчики событий, используя этот механизм. Это не случайно.

Возвращаясь к теме, служба Windows не имеет такой возможности. Он не имеет графического интерфейса и не устанавливает пользовательский поставщик синхронизации. Таким образом, BackgroundWorker не предоставляет функции, полезной в сервисе. Без пользовательского поставщика синхронизации поставщик по умолчанию просто запускает события в потоке потоков. Что бесполезно, вы также можете запустить событие из вашего рабочего потока. Получить события для запуска в другом конкретном потоке очень трудно, если только вы не воссоздаете механизм цикла сообщений или не подключаетесь к соединению Winforms и не создаете смоделированный поток пользовательского интерфейса, используя невидимое окно. Что не является чем-то необычным, кстати.

26
задан moooeeeep 4 April 2017 в 10:14
поделиться

6 ответов

В C ++ итератор обычно не имеет смысла вне контекста начала и конца диапазона. Сам итератор не знает, где находится начало и конец. Поэтому для того, чтобы сделать что-то подобное, вам нужно вместо этого объединить в цепочку диапазоны итераторов - диапазон - это пара итераторов (начало, конец).

См. Документацию boost :: range . Он может предоставлять инструменты для построения цепочки диапазонов. Единственное отличие состоит в том, что они должны быть одного типа и возвращать один и тот же тип итератора. Кроме того, может быть возможно сделать этот дополнительный общий для объединения различных типов диапазонов с чем-то вроде any_iterator, но, возможно, и нет.

4
ответ дан 28 November 2019 в 07:49
поделиться

Я уже писал один раньше (на самом деле, просто для того, чтобы связать две пары итераторов вместе). Это не так уж сложно, особенно если вы используете boost iterator_facade .

Создание итератора ввода (что, по сути, делает цепочка в Python) - простой первый шаг. Поиск правильной категории для итератора, объединяющего комбинацию различных категорий итераторов, оставлен в качестве упражнения для читателя; -).

2
ответ дан 28 November 2019 в 07:49
поделиться

Нет в стандартной библиотеке. Boost может что-то иметь.

Но на самом деле такая вещь должна быть тривиальной для реализации. Просто сделайте себе итератор с вектором итераторов в качестве члена. Какой-то очень простой код для оператора ++, и вот вы.

1
ответ дан 28 November 2019 в 07:49
поделиться

Проверьте Библиотеку шаблонов представлений (VTL) . Он может не предоставлять напрямую «цепной итератор». Но я думаю, что в нем есть все необходимые инструменты / шаблоны для реализации вашего собственного «цепного итератора».


Со страницы VTL:

Представление - это адаптер контейнера, который предоставляет интерфейс контейнера для

  1. частей данных или
  2. реорганизации данных или
  3. преобразованных данных или
  4. подходящая комбинация наборов данных

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

По сравнению с умными итераторами, представления - это просто фабрики умных итераторов.

1
ответ дан 28 November 2019 в 07:49
поделиться

Насколько мне известно, в Boost нет функциональности, реализующей это - я провел довольно обширный поиск.

Я думал, что легко это реализовал на прошлой неделе, но я побежал в загвоздку: STL, поставляемый с Visual Studio 2008, когда включена проверка диапазона, не позволяет сравнивать итераторы из разных контейнеров (т.е. вы не можете сравнивать somevec1.end () с somevec2.end ()). Внезапно реализовать это стало намного сложнее, и я еще не совсем решил, как это сделать.

В прошлом я писал другие итераторы, используя iterator_facade и iterator_adapter из boost, что лучше, чем писать 'raw' итераторы, но я все еще считаю написание собственных итераторов на C ++ довольно беспорядочным.

0
ответ дан 28 November 2019 в 07:49
поделиться

По сути, вы ищете итератор фасада, который абстрагирует обход нескольких последовательностей.

Поскольку вы пришли из среды Python, я предполагаю, что вас больше заботит гибкость а не скорость. Под гибкостью я подразумеваю способность последовательно перебирать различные типы последовательностей вместе (вектор, массив, связанный список, набор и т. Д.), А под скоростью я имею в виду только выделение памяти из стека.

Если это так, тогда вы можете посмотреть any_iterator из Adobe labs: http://stlab.adobe.com/classadobe_1_1any__iterator.html

Этот итератор дает вам возможность перебирать любой тип последовательности во время выполнения. Чтобы связать, у вас будет вектор (или массив) из трех кортежей any_iterators, то есть три any_iterator для каждого диапазона, который вы объединяете вместе (вам нужно три для итерации вперед или назад, если вы просто хотите итерацию вперед, двух будет достаточно).

Допустим, вы хотите последовательно перебрать последовательность целых чисел:

(Непроверенный код псевдо-c ++)

typedef adobe :: any_iterator AnyIntIter;

struct AnyRange { AnyIntIter begin; AnyIntIter curr; AnyIntIter end; };

Вы можете определить диапазон, например:

int int_array [] = {1, 2, 3, 4}; AnyRange sequence_0 = {int_array, int_array, int_array + ARRAYSIZE (int_array)};

Тогда ваш класс RangeIterator будет иметь std :: vector.

<code>
class RangeIterator {
 public:
  RangeIterator() : curr_range_index(0) {}

  template <typename Container>
  void AddAnyRange(Container& c) {
    AnyRange any_range = { c.begin(), c.begin(), c.end() };
    ranges.push_back(any_range);
  }

  // Here's what the operator++() looks like, everything else omitted.
  int operator++() {

     while (true) {
       if (curr_range_index > ranges.size()) {
         assert(false, "iterated too far");
         return 0;
       }
       AnyRange* any_range = ranges[curr_range_index];
       if (curr_range->curr != curr_range->end()) {
         ++(curr_range->curr);
         return *(curr_range->curr);
       }
       ++curr_range_index;      
     }
  }


 private:
  std::vector<AnyRange> ranges;
  int curr_range_index; 
};
</code>

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

2
ответ дан 28 November 2019 в 07:49
поделиться
Другие вопросы по тегам:

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