简体   繁体   中英

Are there any reasons why the StringPiece/StringRef idiom is not more popular?

From the documentation of the StringPiece class in Chromium's source code :

// 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.

Example of use:

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");  
}

This seems like such an important and obvious optimization that I can't understand why it's not more widespread, and why a class similar to StringPiece is not already in the standard.

Are there any reasons why I shouldn't replace the use of string and char* parameters in my own code with this class? Is there anything like it already in the C++ standard libraries?

UPDATE . I've learnt that LLVM's source uses a similar concept: the StringRef class.

Bit later, but ...

Idea behind StringPiece is very good. The class can capture both std::string and const char * and pass them to a function. Here is an example:

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

If function accepted std::string you actually creating a temporary object if you pass const char * and whole char is copied (for example with memcpy ).

You also does not need to worry about livetime, because you are passing StringRef to function / method.

There are such class in:

  • Google - StringPiece

  • boost - boost::string_ref

  • LLVM - StringRef

My own (incomplete) implementation can be seen here:
https://github.com/nmmmnu/HM3/blob/master/include/stringref.h

Update 2016:

In C++17, there are std::string_view . I did not study it in details, but in general it has same idea. Also similar to mine implementation it have constexpr c-tor, so you can create objects at compile time and use it along with other constexpr functions.

The question has been very well answered already, but to give some more context, the StringPiece pattern is very widely used internally at Google and has been for many years. It is strongly recommended in Google coding guidelines, which is almost surely why Chrome (and subsequently Chromium) have adopted it.

StringPiece keeps a pointer to the string data that is passed to its constructor. Thus it relies on the lifetime of that string to be longer than the StringPiece. This is guaranteed if you are using StringPiece as a function parameter; not so if you're keeping a copy of the string in a class member for example.

It's not quite as universal as std::string, and it's definitely not a replacement for it.

The standard is trying to move away from const char* in favor of string altogether, so adding more options for conversion is useless.

Also note that a nice formed program should use either string or const char* all around ;).

StringPiece is great but the pieces aren't null terminated. If you need to pass to lower level interfaces that take null terminated strings, you need to copy the stringpiece into a null terminated string.

(Not everyone has bought into STL or std::string.)

Because why bother? With copy elision and/or pass by reference, memory allocations for std::string can usually be avoided as well.

The string situation in C++ is confusing enough as it is, without adding still more string classes.

If the language was to be redesigned from scratch, or if backwards compatibility wasn't an issue, then this is one of many possible improvements that could be done to string handling in C++. But now that we're stuck with both char* and std::string , adding a stringref-style class into the mix would cause a lot of confusion, with limited benefit.

Apart from this, isn't the same effect achieved more idiomatically with a pair of iterators? If I want to pass a sequence of characters, whether they belong to a string or a char* , why shouldn't I just use a pair of iterators to delimit them?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM