Есть ли причины, по которым идиома StringPiece/StringRef не более популярна?
Из документации класса StringPiece в исходном коде Chromium:
// A string-like object that points to a sized piece of memory.
//
// Functions or methods may use const StringPiece& parameters to accept either
// a "const char*" or a "string" value that will be implicitly converted to
// a StringPiece.
//
// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
// conversions from "const char*" to "string" and back again.
Пример использования:
void foo(StringPiece const & str) // Pass by ref. is probably not needed
{
// str has same interface of const std::string
}
int main()
{
string bar("bar");
foo(bar); // OK, no mem. alloc.
// No mem. alloc. either, would be if arg. of "foo" was std::string
foo("baz");
}
Это кажется такой важной и очевидной оптимизацией, что я не могу понять, почему она не стала более распространенной, и почему класс, подобный StringPiece, еще не находится в стандарте.
Есть ли причины, по которым я не должен заменять использование параметров string
и char*
в моем собственном коде этим классом? Есть ли что-нибудь подобное в стандартных библиотеках С++?
UPDATE. Я узнал, что источник LLVM использует аналогичную концепцию: класс StringRef.
Ответы
Ответ 1
Потому что зачем беспокоиться? При копировании и/или передаче по ссылке обычно можно избежать выделения памяти для std::string
.
Строковая ситуация на С++ довольно запутанна, не добавляя еще более строковых классов.
Если язык должен был быть изменен с нуля или если обратная совместимость не была проблемой, то это одно из многих возможных улучшений, которые можно было бы сделать для обработки строк в С++. Но теперь, когда мы застряли как с char*
, так и с std::string
, добавление класса stringref в этот микс вызывает много путаницы с ограниченной пользой.
Кроме того, это не тот же эффект, который достигается более идиоматически с парой итераторов?
Если я хочу передать последовательность символов, независимо от того, принадлежат они к строке или char*
, почему я не должен использовать пару итераторов, чтобы их разграничить?
Ответ 2
Бит позже, но...
Идея за StringPiece очень хорошая. Класс может захватывать как std::string
, так и const char *
и передавать их функции. Вот пример:
void process(const StringRef s){
// do something
}
process("Hello"); // const char *
std::string s = "Hello";
process(s); // std::string
process(std::string("Hello")); // std::string rvalue
Если функция принята std::string
, вы фактически создаете временный объект, если вы передаете const char *
и весь char скопирован (например, с memcpy
).
Вам также не нужно беспокоиться о жизни, потому что вы передаете StringRef
в функцию/метод.
Есть такой класс в:
Моя собственная (неполная) реализация можно увидеть здесь:
https://github.com/nmmmnu/HM3/blob/master/include/stringref.h
Обновление 2016:
В С++ 17 есть std::string_view
. Я не изучил его подробно, но в целом он имеет ту же идею. Кроме того, аналогично реализации моей, он имеет constexpr
c-tor, поэтому вы можете создавать объекты во время компиляции и использовать их вместе с другими функциями constexpr
.
Ответ 3
Вопрос уже очень хорошо ответил, но, чтобы дать еще какой-то контекст, шаблон StringPiece
очень широко используется внутри компании Google и существует уже много лет. Настоятельно рекомендуется в руководствах по кодированию Google, что почти наверняка означает, что Chrome (и впоследствии Chromium) принял его.
Ответ 4
StringPiece
хранит указатель на строковые данные, которые передаются его конструктору. Таким образом, он полагается на время жизни этой строки дольше, чем StringPiece. Это гарантируется, если вы используете параметр StringPiece в качестве параметра функции; не так, если вы сохраняете копию строки в члене класса, например.
Это не совсем универсально, как std::string, и это определенно не заменяет его.
Ответ 5
Стандарт пытается отойти от const char * в пользу строки в целом, поэтому добавление дополнительных параметров для преобразования бесполезно.
Также обратите внимание на то, что программа с хорошим кодом должна использовать любую строку или const char * все вокруг;).
Ответ 6
StringPiece замечательный, но части не имеют нулевой конец. Если вам нужно перейти на интерфейсы нижнего уровня, которые принимают строки с нулевым завершением, вам нужно скопировать строку в строку с нулевым завершением.
(Не все купили в STL или std::string.)