Когда использовать StringBuilder? [дубликат]

Крайне важно, чтобы сгенерированный код был максимально эффективным.

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

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

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

static_assert(__cplusplus >= 201703L, "example written for C++17 or later");

#include <cstddef>

#include <array>
#include <type_traits>
#include <utility>

namespace detail {

template<std::size_t... inds, class F>
constexpr void gen_inds_impl(std::index_sequence<inds...>, F&& f) {
  f(std::integral_constant<std::size_t, inds>{}...);
}

}// detail

template<std::size_t N, class F>
constexpr void gen_inds(F&& f) {
  detail::gen_inds_impl(std::make_index_sequence<N>{}, std::forward<F>(f));
}

// the code above is reusable

template<
  std::size_t... inds_out,
  class T, std::size_t size_out, std::size_t size_in
>
constexpr std::array<T, size_out> insert1(
  std::array<T, size_out> out,
  std::array<T, size_in> in
) {
  static_assert((... && (inds_out < size_out)));
  static_assert(sizeof...(inds_out) <= size_in);

  gen_inds<sizeof...(inds_out)>([&] (auto... inds_in) {
    ((out[inds_out] = in[inds_in]), ...);
  });

  return out;
}

Аналогичной альтернативой является static_for подход:

static_assert(__cplusplus >= 201703L, "example written for C++17 or later");

#include <cstddef>

#include <array>
#include <type_traits>
#include <utility>

namespace detail {

template<std::size_t... inds, class F>
constexpr void static_for_impl(std::index_sequence<inds...>, F&& f) {
  (f(std::integral_constant<std::size_t, inds>{}), ...);
}

}// detail

template<std::size_t N, class F>
constexpr void static_for(F&& f) {
  detail::static_for_impl(std::make_index_sequence<N>{}, std::forward<F>(f));
}

// the code above is reusable

template<
  std::size_t... inds_out,
  class T, std::size_t size_out, std::size_t size_in
>
constexpr std::array<T, size_out> insert2(
  std::array<T, size_out> out,
  std::array<T, size_in> in
) {
  static_assert(sizeof...(inds_out) >= 1);

  static_assert((... && (inds_out < size_out)));
  static_assert(sizeof...(inds_out) <= size_in);

  constexpr std::size_t N = sizeof...(inds_out);

  static_for<N>([&] (auto n) {
    // note the constexpr
    constexpr std::size_t ind_out = std::array{inds_out...}[n];
    constexpr std::size_t ind_in = n;
    out[ind_out] = in[ind_in];
  });

  return out;
}
16
задан Community 23 May 2017 в 10:29
поделиться

6 ответов

Я имею статья об этой самой теме . Таким образом (скопированный с конца страницы):

  • Определенно использование StringBuilder, когда Вы конкатенируете в нетривиальном цикле - особенно, если Вы не знаете наверняка (во время компиляции), сколько повторений Вы сделаете через цикл. Например, читая файл символ за один раз, создавая строку, когда Вы идете с помощью + =, оператор является потенциально самоубийством производительности.
  • Определенно используют оператор конкатенации, когда можно (четко) указать все, что должно быть связано в одном операторе. (Если у Вас есть массив вещей конкатенировать, рассмотрите Строку вызова. Concat явно - или Строка. Соединение, если Вам нужен разделитель.)
  • не боятся разбить литералы в несколько связанных битов - результатом будет то же. Можно помочь удобочитаемости путем повреждения длинного литерала в несколько строк, например, без вреда производительности.
  • при необходимости в промежуточных результатах конкатенации для чего-то другого, чем питание следующего повторения конкатенации StringBuilder не собирается помогать Вам. Например, если Вы создадите полное имя от имени и фамилии, и затем добавите третью информацию (псевдоним, возможно) в конец, то Вы только извлечете выгоду из использования StringBuilder, если Вам не будет нужно (имя + фамилия) строка для другой цели (как мы делаем в примере, который создает объект Человека).
  • , Если у Вас просто есть несколько конкатенаций, чтобы сделать, и Вы действительно хотите сделать их в отдельных операторах, это действительно не имеет значения, какой путь Вы идете. То, какой путь более эффективен, будет зависеть от количества конкатенаций размеры строки, включенной, и что приказывает, чтобы они были связаны в. Если Вы действительно полагаете, что часть кода, чтобы быть узким местом производительности, представьте или сравнить его оба пути.
36
ответ дан 30 November 2019 в 15:35
поделиться

Вот мое эмпирическое правило:

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

13
ответ дан 30 November 2019 в 15:35
поделиться

Ужас Кодирования имеет хорошую статью относительно этого вопроса, Печальная Трагедия Театра Микрооптимизации .

3
ответ дан 30 November 2019 в 15:35
поделиться

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

0
ответ дан 30 November 2019 в 15:35
поделиться

Кто-то выяснил экспериментально, что критическое число равняется 6. Больше чем 6 конкатенаций подряд и необходимо использовать StringBuilder. Не может помнить, где я нашел это.

Однако примечание это, если Вы просто пишете это в строке:

"qwert" + "yuiop" + "asdf" + "gh" + "jkl;" + "zxcv" + "bnm" + ",."

, Который преобразовывается в один вызов функции (я не знаю, как записать это в VB.net)

String.Concat("qwert", "yuiop", "asdf", "gh", "jkl;", "zxcv", "bnm", ",.");

Поэтому при выполнении всех конкатенаций на одной строке, затем не беспокойтесь StringBuilder потому что Строка. Concat эффективно сделает все конкатенации сразу. Это - только если Вы делаете их в цикле или последовательно конкатенируете.

0
ответ дан 30 November 2019 в 15:35
поделиться

Мое правило - когда Вы добавите к строке в Для или Цикл foreach, используйте StringBuilder.

0
ответ дан 30 November 2019 в 15:35
поделиться
Другие вопросы по тегам:

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