Иногда вам нужно заполнить std::string
символами, созданными функцией C. Типичный пример такой:
constexpr static BUFFERSIZE{256};
char buffer[BUFFERSIZE];
snprint (buffer, BUFFERSIZE, formatstring, value1, value2);
return std::string(buffer);
Обратите внимание, как нам сначала нужно заполнить локальный буфер, а затем скопировать его в std::string
.
Пример становится более сложным, если рассчитывается максимальный размер буфера и не обязательно то, что вы хотите сохранить в стеке. Например:
constexpr static BUFFERSIZE{256};
if (calculatedBufferSize>BUFFERSIZE)
{
auto ptr = std::make_unique<char[]>(calculatedBufferSize);
snprint (ptr.get(), calculatedBufferSize, formatstring, value1, value2);
return std::string(ptr.get());
}
else
{
char buffer[BUFFERSIZE];
snprint (buffer, BUFFERSIZE, formatstring, value1, value2);
return std::string(buffer);
}
Это делает код еще более сложным, и если рассчитанныйBufferSize больше, чем мы хотим в стеке, мы по существу делаем следующее:
- выделить память (make_unique)
- заполнить память желаемым результатом
- выделить память (std :: string)
- копировать память в строку
- освободить память
Так как C ++ 17 std::string
имеет неконстантный метод data()
, подразумевающий, что это способ манипулировать строками. Так что кажется заманчивым сделать это:
std::string result;
result.resize(calculatedBufferSize);
snprint (result.data(), calculatedBufferSize, formatstring, value1, value2);
result.resize(strlen(result.c_str()));
return result;
Мои эксперименты показывают, что последнее изменение размера необходимо, чтобы убедиться, что длина строки сообщается правильно. std::string::length()
не ищет нуль-терминатор, он просто возвращает размер (как и std::vector
).
Обратите внимание, что у нас намного меньше выделения и копирования:
- выделить память (изменить размер строки)
- заполнить память желаемым результатом
Честно говоря, хотя он кажется гораздо более эффективным, он также выглядит очень «нестандартным» для меня. Кто-нибудь может указать, разрешено ли это поведение стандартом C ++ 17? Или есть другой способ сделать этот вид манипуляций более эффективным способом?
Пожалуйста, не обращайтесь к вопросу Управление std :: string , так как этот вопрос о гораздо более грязной логике (даже при использовании memset
).
Также не отвечайте, что я должен использовать потоки C ++ (std::string_stream
, эффективно?, Честно?). Иногда у вас просто есть эффективная логика в C, которую вы хотите использовать повторно.