Это расширение к двум ответам, уже предоставленным выше, поскольку производительность во время выполнения, казалось, была темой в комментариях. Я бы добавил это как комментарии, но у меня пока нет этой привилегии.
Я протестировал 2 реализации на производительность во время выполнения с помощью Visual Studio 2015:
Использование stringstream:
std::stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
result << delimiter;
result << (unsigned short)*it;
}
return result.str();
Использование накопления:
std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
std::to_string(vec[0]),
[&delimiter](std::string& a, uint8_t b) {
return a + delimiter+ std::to_string(b);
});
return result;
Производительность сборки релиза была близка с парой тонкостей.
Реализация накопления была немного быстрее (20-50 мс, ~ 10-30% от общего времени выполнения (~ 180 мс) на 1000 итераций по вектору из 256 элементов). Однако реализация accumulate
была быстрее только тогда, когда параметр a
для лямбда-функции был передан по ссылке. Передача параметра a
по значению привела к аналогичной разнице во времени выполнения в пользу реализации stringstream
. Реализация accumulate
также несколько улучшилась, когда строка результата была возвращена напрямую, а не присвоена локальной переменной, которая была немедленно возвращена. YMMV с другими компиляторами C ++.
Сборка отладки была в 5-10 раз медленнее при использовании accumulate
, поэтому я думаю, что создание дополнительной строки, отмеченное в нескольких комментариях выше, разрешено оптимизатором.
Я смотрел на конкретную реализацию, используя vector
из uint8_t
значений. Полный код теста следует:
#include <vector>
#include <iostream>
#include <sstream>
#include <numeric>
#include <chrono>
using namespace std;
typedef vector<uint8_t> uint8_vec_t;
string concat_stream(const uint8_vec_t& vec, string& delim = string(" "));
string concat_accumulate(const uint8_vec_t& vec, string& delim = string(" "));
string concat_stream(const uint8_vec_t& vec, string& delimiter)
{
stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
result << delimiter;
result << (unsigned short)*it;
}
return result.str();
}
string concat_accumulate(const uint8_vec_t& vec, string& delimiter)
{
return accumulate(next(vec.begin()), vec.end(),
to_string(vec[0]),
[&delimiter](string& a, uint8_t b) {
return a + delimiter + to_string(b);
});
}
int main()
{
const int elements(256);
const int iterations(1000);
uint8_vec_t test(elements);
iota(test.begin(), test.end(), 0);
int i;
auto stream_start = chrono::steady_clock::now();
string join_with_stream;
for (i = 0; i < iterations; ++i) {
join_with_stream = concat_stream(test);
}
auto stream_end = chrono::steady_clock::now();
auto acc_start = chrono::steady_clock::now();
string join_with_acc;
for (i = 0; i < iterations; ++i) {
join_with_acc = concat_accumulate(test);
}
auto acc_end = chrono::steady_clock::now();
cout << "Stream Results:" << endl;
cout << " elements: " << elements << endl;
cout << " iterations: " << iterations << endl;
cout << " runtime: " << chrono::duration<double, milli>(stream_end - stream_start).count() << " ms" << endl;
cout << " result: " << join_with_stream << endl;
cout << "Accumulate Results:" << endl;
cout << " elements: " << elements << endl;
cout << " iterations: " << iterations << endl;
cout << " runtime: " << chrono::duration<double, milli>(acc_end - acc_start).count() << " ms" << endl;
cout << " result:" << join_with_acc << endl;
return 0;
}