...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
The class boost::string_view
and other classes derived from basic_string_view
represent references
to strings or substrings. When you are parsing/processing strings from
some external source, frequently you want to pass a piece of text to a
procedure for specialized processing. Before std::string_view
, the canonical way
to do this used to be a std::string
, but that has certain
drawbacks:
1) If you are processing a buffer of text (say a HTTP response or the contents of a file), then you have to create the string from the text you want to pass, which involves memory allocation and copying of data.
2) If a routine receives a constant std::string
and wants to pass a portion
of that string to another routine, then it must create a new string of
that substring.
3) If a routine receives a constant std::string
and wants to return a
portion of the string, then it must create a new string to return.
boost::string_view
is designed to solve these efficiency problems. A boost::string_view
is a read-only reference
to a contiguous sequence of characters, and provides much of the functionality
of std::string
. A boost::string_view
is cheap to create,
copy and pass by value, because it does not actually own the storage that
it points to.
A boost::string_view
is implemented as a small struct that contains a pointer to the start of
the character data
and
a count
. A boost::string_view
is cheap to create
and cheap to copy.
boost::string_view
acts as a container; it includes all the methods that you would expect
in a container, including iteration support, operator[]
, at
and size
. It can be used
with any of the iterator-based algorithms in the STL - as long as you do
not need to change the underlying data. For example, std::sort
and std::remove
will not work.
Besides generic container functionality, boost::string_view
provides a subset
of the interface of std::string
. This makes it easy to
replace parameters of type const
with std::string
&boost::string_view
.
Like std::string
, boost::string_view
has a static member
variable named npos
to
denote the result of failed searches, and to mean "the end".
Caution | |
---|---|
Because a |
Note | |
---|---|
Boost.Utility also includes the class
-
-
Please prefer
- The
-
- Code that uses
- Not much code depends on |
Integrating string_view
into your code is fairly simple. Wherever you pass a const
or std::string
&std::string
as a parameter, that's
a candidate for passing a boost::string_view
.
std::string
extract_part ( conststd::string
&bar ) { return bar.substr ( 2, 3 ); } if ( extract_part ( "ABCDEFG" ).front() == 'C' ) { /* do something */ }
Let's figure out what happens in this contrived example.
"ABCDEFG"
, and it is passed
(by reference) to the routine extract_part
.
std::string
::substr
and returned to extract_part
(this copy may be elided
by RVO).
extract_part
returns
that string back to the caller (again this copy may be elided).
front
is called on the second string, and then it is deallocated as well.
Two std::string
s are created, and two
copy operations. That is potentially four memory allocations and deallocations,
and the associated copying of data.
Now let's look at the same code with string_view
:
boost::string_view
extract_part (boost::string_view
bar ) { return bar.substr ( 2, 3 ); } if ( extract_part ( "ABCDEFG" ).front() == "C" ) { /* do something */ }
No memory allocations. No copying of character data. No changes to the
code other than the types. There are two string_view
s created, and two
string_view
s copied, but those are cheap operations.
The header file <boost/utility/string_view.hpp>
defines a template boost::basic_string_view
, and four specializations
string_view
,
wstring_view
,
u16string_view
,
u32string_view
- for char
/ wchar_t
/ char16_t
/ char32_t
.
#include <boost/utility/string_view.hpp>
Construction and copying:
constexpr basic_string_view (); // Constructs an empty string_view
constexpr basic_string_view(const charT* str); // Constructs from a NULL-terminated string
constexpr basic_string_view(const charT* str, size_type len); // Constructs from a pointer, length pair
template<typename Allocator>
basic_string_view(const std::basic_string
<charT, traits, Allocator>& str); // Constructs from a std::string
basic_string_view (const basic_string_view &rhs);
basic_string_view& operator=(const basic_string_view &rhs);
string_view
does not define a move constructor nor a move-assignment operator because
copying a string_view
is just a cheap as moving one.
Basic container-like functions:
constexpr size_type size() const ; constexpr size_type length() const ; constexpr size_type max_size() const ; constexpr bool empty() const ; // All iterators are const_iterators constexpr const_iterator begin() const ; constexpr const_iterator cbegin() const ; constexpr const_iterator end() const ; constexpr const_iterator cend() const ; const_reverse_iterator rbegin() const ; const_reverse_iterator crbegin() const ; const_reverse_iterator rend() const ; const_reverse_iterator crend() const ;
Access to the individual elements (all of which are const):
constexpr const charT& operator[](size_type pos) const ; const charT& at(size_t pos) const ; constexpr const charT& front() const ; constexpr const charT& back() const ; constexpr const charT* data() const ;
Modifying the string_view
(but not the underlying data):
void clear(); void remove_prefix(size_type n); void remove_suffix(size_type n);
Searching:
size_type find(basic_string_view s) const ; size_type find(charT c) const ; size_type rfind(basic_string_view s) const ; size_type rfind(charT c) const ; size_type find_first_of(charT c) const ; size_type find_last_of (charT c) const ; size_type find_first_of(basic_string_view s) const ; size_type find_last_of(basic_string_view s) const ; size_type find_first_not_of(basic_string_view s) const ; size_type find_first_not_of(charT c) const ; size_type find_last_not_of(basic_string_view s) const ; size_type find_last_not_of(charT c) const ;
String-like operations:
constexpr basic_string_view substr(size_type pos, size_type n=npos) const ; // Creates a new string_view bool starts_with(charT c) const ; bool starts_with(basic_string_view x) const ; bool ends_with(charT c) const ; bool ends_with(basic_string_view x) const ;
basic_streambuf
and refactored that functionality into a common utility.
namespace boost { template<typename charT, typename traits> class basic_string_view; template<typename charT, typename traits> constexpr bool operator==(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator!=(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator<(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator>(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator<=(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator>=(basic_string_view< charT, traits > x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator==(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator==(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator==(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator==(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator!=(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator!=(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator!=(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator!=(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator<(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator<(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator<(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator<(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator>(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator>(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator>(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator>(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator<=(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator<=(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator<=(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator<=(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits, typename Allocator> constexpr bool operator>=(basic_string_view< charT, traits > x, const std::basic_string< charT, traits, Allocator > & y); template<typename charT, typename traits, typename Allocator> constexpr bool operator>=(const std::basic_string< charT, traits, Allocator > & x, basic_string_view< charT, traits > y); template<typename charT, typename traits> constexpr bool operator>=(basic_string_view< charT, traits > x, const charT * y); template<typename charT, typename traits> constexpr bool operator>=(const charT * x, basic_string_view< charT, traits > y); template<typename charT, typename traits> std::basic_ostream< charT, traits > & operator<<(std::basic_ostream< charT, traits > & os, const basic_string_view< charT, traits > & str); template<typename It> std::size_t hash_range(It, It); template<typename charT, typename traits> std::size_t hash_value(basic_string_view< charT, traits > s); }