Какой контейнер STL я должен использовать для FIFO?

/
^                                             # start of string
(                                             # first group start
  (?:
    (?:[^?+*{}()[\]\\|]+                      # literals and ^, $
     | \\.                                    # escaped characters
     | \[ (?: \^?\\. | \^[^\\] | [^\\^] )     # character classes
          (?: [^\]\\]+ | \\. )* \]
     | \( (?:\?[:=!]|\?<[=!]|\?>)? (?1)?? \)  # parenthesis, with recursive content
     | \(\? (?:R|[+-]?\d+) \)                 # recursive matching
     )
    (?: (?:[?+*]|\{\d+(?:,\d*)?\}) [?+]? )?   # quantifiers
  | \|                                        # alternative
  )*                                          # repeat content
)                                             # end first group
$                                             # end of string
/

Это - рекурсивный regex и не поддерживается многими regex механизмами. PCRE базировался, должны поддерживать его.

Без пробела и комментариев:

/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/
<час>

.NET не поддерживает рекурсию непосредственно. ((?1) и (?R) конструкции.) Рекурсия должна была бы быть преобразована в подсчет сбалансированных групп:

^                                         # start of string
(?:
  (?: [^?+*{}()[\]\\|]+                   # literals and ^, $
   | \\.                                  # escaped characters
   | \[ (?: \^?\\. | \^[^\\] | [^\\^] )   # character classes
        (?: [^\]\\]+ | \\. )* \]
   | \( (?:\?[:=!]
         | \?<[=!]
         | \?>
         | \?<[^\W\d]\w*>
         | \?'[^\W\d]\w*'
         )?                               # opening of group
     (?<N>)                               #   increment counter
   | \)                                   # closing of group
     (?<-N>)                              #   decrement counter
   )
  (?: (?:[?+*]|\{\d+(?:,\d*)?\}) [?+]? )? # quantifiers
| \|                                      # alternative
)*                                        # repeat content
$                                         # end of string
(?(N)(?!))                                # fail if counter is non-zero.

Уплотненный:

^(?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>|\?<[^\W\d]\w*>|\?'[^\W\d]\w*')?(?<N>)|\)(?<-N>))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*$(?(N)(?!))
84
задан Gab Royer 11 August 2009 в 20:45
поделиться

6 ответов

Поскольку существует множество ответов, вы можете запутаться, но резюмируем:

Используйте std :: queue . Причина этого проста: это структура FIFO. Вам нужен FIFO, вы используете std :: queue .

Это проясняет ваши намерения для всех, и даже для вас самих. A std :: list или std :: deque - нет. Список можно вставлять и удалять где угодно, что не является тем, что предполагает структура FIFO, и двухсторонняя очередь может добавлять и удалять с любого конца, что также не может сделать структура FIFO.

Вот почему вам следует использовать очередь .

Теперь вы спросили о производительности. Во-первых, всегда помните это важное практическое правило: Хороший код в первую очередь, производительность в последнюю очередь.

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

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

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

Итак, какой базовый контейнер вам следует использовать? Мы знаем, что std :: list и std :: deque оба предоставляют необходимые функции ( push_back () , pop_front () и front () ), так как же нам решить?

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

deque , с другой стороны, выделяется по частям. Он будет выделять реже, чем список . Думайте об этом как о списке, но каждый блок памяти может содержать несколько узлов. (Конечно, я бы посоветовал вам действительно узнать, как это работает .)

Итак, только с этим двухсторонняя очередь должна работать лучше, потому что она не работает » Не так часто занимаюсь памятью. В сочетании с тем фактом, что вы обрабатываете данные постоянного размера, им, вероятно, не придется выделять память после первого прохода через данные, тогда как список будет постоянно выделять и освобождать.

Вторая вещь, которую следует понять, это ] производительность кеша . Выход в ОЗУ происходит медленно, поэтому, когда ЦП действительно в этом нуждается, он максимально использует это время, забирая с собой часть памяти обратно в кеш. Поскольку двухсторонняя очередь выделяется в блоках памяти, вполне вероятно, что доступ к элементу в этом контейнере заставит ЦП также вернуть остальную часть контейнера. Теперь любые дальнейшие обращения к двухсторонней очереди будут быстрыми, потому что данные находятся в кэше.

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

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

Но помните: заставьте код работать с чистым интерфейсом, а затем беспокойтесь о производительности.

Джон выражает обеспокоенность тем, что упаковка списка или двухсторонней очереди вызовет снижение производительности. Еще раз, он и я не можем сказать наверняка, не анализируя сами, но есть вероятность, что компилятор встроит вызовы, которые делает очередь . То есть, когда вы говорите queue.push () , на самом деле он просто скажет queue.container.push_back () , полностью пропуская вызов функции.

Еще раз, это это только обоснованное предположение, но использование очереди не приведет к снижению производительности по сравнению с использованием базового контейнера raw. Как я уже сказал, используйте очередь , потому что она чистая, простая в использовании и безопасная, и если она действительно становится проблемой, профиль и тест.

но использование очереди не приведет к снижению производительности по сравнению с использованием базового контейнера raw. Как я уже сказал, используйте очередь , потому что она чистая, простая в использовании и безопасная, и если она действительно становится проблемой, профиль и тест.

но использование очереди не приведет к снижению производительности по сравнению с использованием базового контейнера raw. Как я уже сказал, используйте очередь , потому что она чистая, простая в использовании и безопасная, и если она действительно становится проблемой, профиль и тест.

180
ответ дан 24 November 2019 в 08:27
поделиться

Проверить std :: queue . Он является оболочкой для базового типа контейнера, а контейнер по умолчанию - std :: deque .

27
ответ дан 24 November 2019 в 08:27
поделиться

Я постоянно push_back новые элементы а pop_front - самый старый элемент (примерно в миллион раз.)

Миллион - это не так уж и много для вычислений. Как предлагали другие, используйте std :: queue в качестве первого решения. В том маловероятном случае, если это будет слишком медленно, определите узкое место с помощью профилировщика (не угадайте!) И повторно реализуйте его, используя другой контейнер с тем же интерфейсом.

7
ответ дан 24 November 2019 в 08:27
поделиться

Почему не std :: queue ? Все, что у него есть, это push_back и pop_front .

5
ответ дан 24 November 2019 в 08:27
поделиться

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

То же самое и со списком . Все зависит от выбора API, который вам нужен.

3
ответ дан 24 November 2019 в 08:27
поделиться

В случае, если кто-то еще выходит вниз по этому проспекту, ответ - это вы можете сделать это, с отражением, за исключением того, что вы не можете, потому что в рамках в рамках. Вот как вы это сделаете:

Dim prop As PropertyDescriptor = TypeDescriptor.GetProperties(GetType(UserInfo))("Age")
Dim att As CategoryAttribute = DirectCast(prop.Attributes(GetType(CategoryAttribute)), CategoryAttribute)
Dim cat As FieldInfo = att.GetType.GetField("categoryValue", BindingFlags.NonPublic Or BindingFlags.Instance)
cat.SetValue(att, "A better description")

все хорошо и хорошо, за исключением того, что атрибут категории изменен для всех свойств, а не просто «возраст».

-121--922349-

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

10
ответ дан 24 November 2019 в 08:27
поделиться
Другие вопросы по тегам:

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