Правильный способ преобразования (много!) чисел в строки без выделения в Qt

tl; dr

Я хочу позвонить QString::number(int) много раз в секунду. Это очень медленно: кажется, что он выделяет новую строку каждый раз. Пытался использовать setNum на той же строке вместо этого, по-прежнему нет радости.


оригинальный, длинный вопрос:

проблема

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

QString allData;
foreach(const int & value, values) {
    allData += QString::number(value);
    allData += 'n';
}

это займет около 280ms на 150000 целыми на моей машине, которая, кажется, много для меня. Я полагаю, это потому, что QString::number вызывается 150000 раз и каждый раз выделяет новую строку. Это каким-то образом подтверждено, что корень проблемы, когда я пытаюсь использовать itoa (который не выделяет память) вместо этого.

возможно, но не на Qt [not-cute] решение

QString allData;
char buffer[100];                               // <-------
foreach(const int & value, values) {
    _itoa_s(value, buffer, sizeof(buffer), 10); // <-------
    allData += buffer;
    allData += 'n';
}

это займет около 70мс в той же 150000 целые числа (около быстрее), что теперь приемлемо для меня (я думаю, что могу сделать что-то с конкатенацией строк, но давайте оставим это за пределами этого вопроса)

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

тогда я вспомнил, что есть еще экземпляр способ: QString::setNum. Я надеялся, что смогу использовать тот же шаблон, что и с itoa: выделите только одну строку и измените ее каждый раз.

желательно, но не работает решение

QString allData;
QString number;                       // <-------
foreach(const int & value, values) {
    number.setNum(value);             // <-------
    allData += number;
    allData += 'n';
}

к сожалению, это не имеет большого значения от QString::number: снова о 280ms, ну, может быть 250мс но все-таки слишком много.

Итак, поздравляю, если вы достигли здесь :) и, наконец...

вопрос(ы)

  1. что посоветовали бы мне эксперты Qt сделать? Заткнись и используй itoa несмотря на отчетливый запах C в противном случае ароматный код C++ / Qt?
  2. или я могу как-то сказать "давай, Qstring, просто съешь это число в себя" ?
  3. интересно почему setNum не делать трик!--34-->?

    Примечания:

    1 в фактическом коде у меня есть не только 150000 целых чисел, но и 50000 тройки целых чисел, которые я также добавляю 't' между ними. Это единственное отличие от моего фактического кода, и я думаю, это не важно: здесь меня интересует только производительность QString::number vs itoa.

    2 на самом деле, я был удивлен, что MinGW также имеет _itoa_s это ведет себя так же, как визуальный Studio, но у меня все еще есть неловкое чувство, что использование такой грязной функции в моем полированном коде Qt уменьшает его переносимость. Поправьте меня, если я ошибаюсь.

2 ответов


вы можете попробовать с QByteArray, который разделяет тот же интерфейс QString, но более подходит для проблем с производительностью.Я получаю 36 МС (Qt 5.2 clang) против ваших исходных 57 МС (на моей машине) с этим кодом:

QByteArray allDatab;
foreach(const int & value, values) {
    allDatab += QByteArray::number(value);
    allDatab += '\n';
}
QString result(allDatab);

и 29 МС с этой версией (что, возможно, подтверждает ваши предположения о setNum):

QByteArray allDatad;
QByteArray number;                       
foreach(const int & value, values) {
    number.setNum(value);             
    allDatad += number;
    allDatad += '\n';
}

как насчет использования STL?

Я проверил ваш код (изменение цикла для упрощения)

int main() {
  stringstream ss;
  for(int i=0; i<2000000; ++i) {
     ss << i << "\n";
  }
}

и я

time ./ss_test
  real  0m0.146s
  user  0m0.139s
  sys   0m0.006s

С версией Qt (в моей машине)

int main() {
  QString allData;
  for(int i=0; i<2000000; ++i) {
    allData += QString::number(i);
    allData += '\n';
  }
}

получить

time ./qtstring_test 
   real 0m0.516s
   user 0m0.508s
   sys  0m0.008s