BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslstl_string

Functions

template<class CHAR_TYPE , class CHAR_TRAITS >
bool bslstl_string_fill (std::basic_ostream< CHAR_TYPE, CHAR_TRAITS > &os, std::basic_streambuf< CHAR_TYPE, CHAR_TRAITS > *buf, std::size_t n)
 Do not use, for internal use by operator<< only.
 

Detailed Description

Outline

Purpose

Provide a standard-compliant basic_string class template.

Classes

Canonical header: bsl_string.h

See also
ISO C++ Standard, Section 21 [strings]

Description

This component defines a single class template basic_string , implementing standard containers, std::string and std::wstring, that hold a sequence of characters.

An instantiation of basic_string is an allocator-aware, value-semantic type whose salient attributes are its size (number of characters) and the sequence of characters that the string contains. The basic_string class is parameterized by the character type, CHAR_TYPE, that character type's traits, CHAR_TRAITS, and an allocator, ALLOCATOR. The traits for each character type provide functions that assign, compare, and copy a sequence of those characters.

A basic_string meets the requirements of a sequential container with random access iterators as specified in the [basic.string] section of the C++ standard [21.4]. The basic_string implemented here adheres to the C++11 standard, except that it does not have template specializations std::u16string and std::u32string. Note that excluded C++11 features are those that require (or are greatly simplified by) C++11 compiler support.

Memory Allocation

The type supplied as a basic_string s ALLOCATOR template parameter determines how that basic_string will allocate memory. The basic_string template supports allocators meeting the requirements of the C++11 standard, in addition it supports scoped-allocators derived from the bslma::Allocator memory allocation protocol. Clients intending to use bslma style allocators should use the template's default ALLOCATOR type: The default type for the ALLOCATOR template parameter, bsl::allocator, provides a C++11 standard-compatible adapter for a bslma::Allocator object.

bslma-Style Allocators

If the (template parameter) type ALLOCATOR of an basic_string instantiation is bsl::allocator, then objects of that basic_string type will conform to the standard behavior of a bslma-allocator-enabled type. Such a basic_string accepts an optional bslma::Allocator argument at construction. If the address of a bslma::Allocator object is explicitly supplied at construction, it is used to supply memory for the basic_string throughout its lifetime; otherwise, the basic_string will use the default allocator installed at the time of the basic_string 's construction (see bslma_default ).

Lexicographical Comparisons

Two basic_string s lhs and rhs are lexicographically compared by first determining N, the smaller of the lengths of lhs and rhs, and comparing characters at each position between 0 and N - 1, using CHAR_TRAITS::lt in lexicographical fashion. If CHAR_TRAITS::lt determines that strings are non-equal (smaller or larger), then this is the result. Otherwise, the lengths of the strings are compared and the shorter string is declared the smaller. Lexicographical comparison returns equality only when both strings have the same length and the same character value in each respective position.

Operations

This section describes the run-time complexity of operations on instances of basic_string :

Legend
------
'V' - the 'CHAR_TYPE' template parameter type of the
'basic_string'
'a', 'b' - two distinct objects of type 'basic_string<V>'
'k' - an integral number
'al' - an STL-style memory allocator
'i1', 'i2' - two iterators defining a sequence of 'CHAR_TYPE'
characters
'v' - an object of type 'V'
'p1', 'p2' - two iterators belonging to 'a'
distance(i1,i2) - the number of values in the range [i1, i2)
+-----------------------------------------+-------------------------------+
| Operation | Complexity |
|=========================================+===============================|
| basic_string<V> a (default construction)| O[1] |
| basic_string<V> a(al) | |
|-----------------------------------------+-------------------------------|
| basic_string<V> a(b) (copy construction)| O[n] |
| basic_string<V> a(b, al) | |
|-----------------------------------------+-------------------------------|
| basic_string<V> a(std::move(b)) | O[1] |
| (move construction) | |
|-----------------------------------------+-------------------------------|
| basic_string<V> a(std::move(b), a1) | O[n] |
| (extended move construction) | |
|-----------------------------------------+-------------------------------|
| basic_string<V> a(k) | O[n] |
| basic_string<V> a(k, al) | |
|-----------------------------------------+-------------------------------|
| basic_string<V> a(i1, i2) | O[distance(i1,i2)] |
| basic_string<V> a(i1, i2, al) | |
|-----------------------------------------+-------------------------------|
| a.~basic_string<V>() (destruction) | O[1] |
|-----------------------------------------+-------------------------------|
| get_allocator() | O[1] |
|-----------------------------------------+-------------------------------|
| a.begin(), a.end(), | O[1] |
| a.cbegin(), a.cend(), | |
| a.rbegin(), a.rend(), | |
| a.crbegin(), a.crend() | |
|-----------------------------------------+-------------------------------|
| a.size() | O[1] |
|-----------------------------------------+-------------------------------|
| a.max_size() | O[1] |
|-----------------------------------------+-------------------------------|
| a.resize(k) | O[k] |
| a.resize(k, v) | |
|-----------------------------------------+-------------------------------|
| a.resize_and_overwrite(k, op) | O[k] |
|-----------------------------------------+-------------------------------|
| a.empty() | O[1] |
|-----------------------------------------+-------------------------------|
| a.reserve(k) | O[1] |
|-----------------------------------------+-------------------------------|
| a.shrink_to_fit() | O[n] |
|-----------------------------------------+-------------------------------|
| a[k] | O[1] |
|-----------------------------------------+-------------------------------|
| a.at(k) | O[1] |
|-----------------------------------------+-------------------------------|
| a.front() | O[1] |
|-----------------------------------------+-------------------------------|
| a.back() | O[1] |
|-----------------------------------------+-------------------------------|
| a.push_back() | O[1] |
|-----------------------------------------+-------------------------------|
| a.pop_back() | O[1] |
|-----------------------------------------+-------------------------------|
| a += b; | O[n] |
|-----------------------------------------+-------------------------------|
| a.append(b); | O[n] |
|-----------------------------------------+-------------------------------|
| a.assign(b); | O[n] |
|-----------------------------------------+-------------------------------|
| a.assign(std::move(b)); | O[1] if the allocator can be |
| | propagated on container move |
| | assignment or 'a' and 'b' use |
| | the same allocator; O[n] |
| | otherwise |
|-----------------------------------------+-------------------------------|
| a.assign(k, v) | O[k] |
|-----------------------------------------+-------------------------------|
| a.assign(i1, i2) | O[distance(i1,i2)] |
|-----------------------------------------+-------------------------------|
| a.insert(p1, v) | O[1 + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.insert(p1, k, v) | O[k + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.insert(p1, i1, i2) | O[distance(i1, i2) |
| | + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.erase(p1) | O[1 + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.erase(p1, p2) | O[1 + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.swap(b), swap(a, b) | O[1] if 'a' and 'b' allocators|
| | compare equal, O[n + m] |
| | otherwise |
|-----------------------------------------+-------------------------------|
| a.clear() | O[1] |
|-----------------------------------------+-------------------------------|
| a = b; (assignment) | O[n] |
|-----------------------------------------+-------------------------------|
| a = std::move(b); (move assignment) | O[1] if the allocator can be |
| | propagated on container move |
| | assignment or 'a' and 'b' use |
| | the same allocator; O[n] |
| | otherwise |
|-----------------------------------------+-------------------------------|
| a == b, a != b | O[n] |
|-----------------------------------------+-------------------------------|
| a < b, a <= b, a > b, a >= b | O[n] |
+-----------------------------------------+-------------------------------+

User-defined literals

The user-defined literal operators are declared for the bsl::string and bsl::wstring types. The ud-suffix _s is chosen to distinguish between the bsl-string's user-defined literal operators and the std-string's user-defined literal operator ""s introduced in the C++14 standard and implemented in the standard library provided by the compiler vendor. Note that the bsl-string's operator "" _s, unlike the std-string's operator ""s, can be used in a client's code if the compiler supports the C++11 standard. Also note that if the compiler supports the C++14 standard then the std-string's operator ""s can be used to initialize a bsl-string as follows:

using namespace std::string_literals;
bsl::string str = "test"s;
Definition bslstl_string.h:1281

however such initialization introduces significant performance overhead due to extra std-string object creation/destruction.

Also note that bsl-string's user-defined literal operators are declared in the bsl::literals::string_literals namespace, where literals and string_literals are inline namespaces. Access to these operators can be gained with either using namespace bsl::literals, using namespace bsl::string_literals or using namespace bsl::literals::string_literals. But we recommend using namespace bsl::string_literals to minimize the scope of the using declaration:

using namespace bsl::string_literals;
bsl::string str = "test"_s;

Memory Allocation For a File-Scope Strings

The operator "" _s uses the currently installed default allocator to supply memory. Note that the default allocator can become locked prior to entering main as a side-effect of initializing a file-scope static string object using operator "" _s. To avoid the default allocator locking an operator "" _S can be used instead. This operator uses the global allocator to supply memory and has no side-effects. (See the "Default Allocator" section in the bslma::Default component-level documentation for details.) For Example:

using namespace bsl::string_literals;
static const bsl::string s = "Use '_S' to initialize a file-scope string"_S;

Usage

In this section we show intended use of this component.

Example 1: Basic Syntax

In this example, we will show how to create and use the string typedef.

First, we will default-construct a string object:

assert(s.empty());
assert(0 == s.size());
assert("" == s);
size_type size() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6592
bool empty() const BSLS_KEYWORD_NOEXCEPT
Return true if this string has length 0, and false otherwise.
Definition bslstl_string.h:6631

Then, we will construct a string object from a string literal:

bsl::string t = "Hello World";
assert(!t.empty());
assert(11 == t.size());
assert("Hello World" == t);

Next, we will clear the contents of t and assign it a couple of values: first from a string literal; and second from another string object:

t.clear();
assert(t.empty());
assert("" == t);
t = "Good Morning";
assert(!t.empty());
assert("Good Morning" == t);
t = s;
assert(t.empty());
assert("" == t);
assert(t == s);
void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:5430

Then, we will create three string objects: the first representing a street name, the second a state, and the third a ZIP code. We will then concatenate them into a single address string and print the contents of that string on standard output:

const bsl::string street = "731 Lexington Avenue";
const bsl::string state = "NY";
const bsl::string zipCode = "10022";
const bsl::string fullAddress = street + " " + state + " " + zipCode;
bsl::cout << fullAddress << bsl::endl;

The above print statement should produce a single line of output:

731 Lexington Avenue NY 10022

Then, we search the contents of address (using the find function) to determine if it lies on a specified street:

const bsl::string streetName = "Lexington";
if (bsl::string::npos != fullAddress.find(streetName, 0)) {
bsl::cout << "The address " << fullAddress << " is located on "
<< streetName << "." << bsl::endl;
}
size_type find(const basic_string &substring, size_type position=0) const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6732
static const size_type npos
Definition bslstl_string.h:1676

Next, we show how to get a reference providing modifiable access to the null-terminated string literal stored by a string object using the c_str function. Note that the returned string literal can be passed to various standard functions expecting a null-terminated string:

const bsl::string v = "Another string";
const char *cs = v.c_str();
assert(bsl::strlen(cs) == v.size());
const CHAR_TYPE * c_str() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6705

Then, we construct two string objects, x and y, using a user-specified allocator:

bslma::TestAllocator allocator1, allocator2;
const char *SHORT_STRING = "A small string";
const char *LONG_STRING = "This long string would definitely cause "
"memory to be allocated on creation";
const bsl::string x(SHORT_STRING, &allocator1);
const bsl::string y(LONG_STRING, &allocator2);
assert(SHORT_STRING == x);
assert(LONG_STRING == y);
Definition bslma_testallocator.h:384

Notice that, no memory was allocated from the allocator for object x because of the short-string optimization used in the string type.

Finally, we can track memory usage of x and y using allocator1 and allocator2 and check that memory was allocated only by allocator2:

assert(0 == allocator1.numBlocksInUse());
assert(1 == allocator2.numBlocksInUse());
bsls::Types::Int64 numBlocksInUse() const
Definition bslma_testallocator.h:1087

Example 2: string as a data member

The most common use of string objects are as data members in user-defined classes. In this example, we will show how string objects can be used as data members.

First, we begin to define a class, Employee, that represents the data corresponding to an employee of a company:

/// This simply constrained (value-semantic) attribute class represents
/// the information about an employee. An employee's first and last
/// name are represented as `string` objects and their employee
/// identification number is represented by an `int`. Note that the
/// class invariants are identically the constraints on the individual
/// attributes.
///
/// This class:
/// * supports a complete set of *value-semantic* operations
/// - except for BDEX serialization
/// * is **exception-neutral** (agnostic)
/// * is **alias-safe**
/// * is `const` **thread-safe**
class Employee {
// DATA
bsl::string d_firstName; // first name
bsl::string d_lastName; // last name
int d_id; // identification number

Next, we define the creators for this class:

public:
// CREATORS
/// Create a `Employee` object having the (default) attribute
/// values:
/// ```
/// firstName() == ""
/// lastName() == ""
/// id() == 0
/// ```
/// Optionally specify a `basicAllocator` used to supply memory. If
/// `basicAllocator` is 0, the currently installed default
/// allocator is used.
Employee(bslma::Allocator *basicAllocator = 0);
/// Create a `Employee` object having the specified `firstName`,
/// `lastName`, and `id` attribute values. Optionally specify a
/// `basicAllocator` used to supply memory. If `basicAllocator` is
/// 0, the currently installed default allocator is used.
Employee(const bsl::string_view& firstName,
const bsl::string_view& lastName,
int id,
bslma::Allocator *basicAllocator = 0);
/// Create a `Employee` object having the same value as the
/// specified `original` object. Optionally specify a
/// `basicAllocator` used to supply memory. If `basicAllocator` is
/// 0, the currently installed default allocator is used.
Employee(const Employee& original,
bslma::Allocator *basicAllocator = 0);
/// Destroy this object.
//! ~Employee() = default;
Definition bslstl_stringview.h:441
Definition bslma_allocator.h:457

Notice that all constructors of the Employee class are optionally provided an allocator that is then passed through to the string data members of Employee. This allows the user to control how memory is allocated by Employee objects. Also note that the type of the firstName and lastName arguments of the value constructor is bsl::string_view. The bsl::string_view allows specifying a string or a const char * to represent a string value. For the sake of brevity its implementation is not explored here.

Then, declare the remaining methods of the class:

// MANIPULATORS
/// Assign to this object the value of the specified `rhs` object,
/// and return a reference providing modifiable access to this
/// object.
Employee& operator=(const Employee& rhs);
/// Set the `firstName` attribute of this object to the specified
/// `value`.
void setFirstName(const bsl::string_view& value);
/// Set the `lastName` attribute of this object to the specified
/// `value`.
void setLastName(const bsl::string_view& value);
/// Set the `id` attribute of this object to the specified `value`.
void setId(int value);
// ACCESSORS
/// Return a reference providing non-modifiable access to the
/// `firstName` attribute of this object.
const bsl::string& firstName() const;
/// Return a reference providing non-modifiable access to the
/// `lastName` attribute of this object.
const bsl::string& lastName() const;
/// Return the value of the `id` attribute of this object.
int id() const;
};

Next, we declare the free operators for Employee:

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise. Two `Employee` objects have the
/// same value if all of their corresponding values of their
/// `firstName`, `lastName`, and `id` attributes are the same.
inline
bool operator==(const Employee& lhs, const Employee& rhs);
/// Return `true` if the specified `lhs` and `rhs` objects do not have
/// the same value, and `false` otherwise. Two `Employee` objects do
/// not have the same value if any of the corresponding values of their
/// `firstName`, `lastName`, or `id` attributes are not the same.
inline
bool operator!=(const Employee& lhs, const Employee& rhs);

Then, we implement the various methods of the Employee class:

// CREATORS
inline
Employee::Employee(bslma::Allocator *basicAllocator)
: d_firstName(basicAllocator)
, d_lastName(basicAllocator)
, d_id(0)
{
}
inline
Employee::Employee(const bsl::string_view& firstName,
const bsl::string_view& lastName,
int id,
bslma::Allocator *basicAllocator)
: d_firstName(firstName.begin(), firstName.end(), basicAllocator)
, d_lastName(lastName.begin(), lastName.end(), basicAllocator)
, d_id(id)
{
BSLS_ASSERT_SAFE(!firstName.empty());
BSLS_ASSERT_SAFE(!lastName.empty());
}
inline
Employee::Employee(const Employee& original,
bslma::Allocator *basicAllocator)
: d_firstName(original.d_firstName, basicAllocator)
, d_lastName(original.d_lastName, basicAllocator)
, d_id(original.d_id)
{
}
BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT
Return true if this view has length 0, and false otherwise.
Definition bslstl_stringview.h:1703
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762

Notice that the basicAllocator parameter can simply be passed as an argument to the constructor of bsl::string.

Now, we implement the remaining manipulators of the Employee class:

// MANIPULATORS
inline
Employee& Employee::operator=(const Employee& rhs)
{
d_firstName = rhs.d_firstName;
d_lastName = rhs.d_lastName;
d_id = rhs.d_id;
return *this;
}
inline
void Employee::setFirstName(const bsl::string_view& value)
{
d_firstName.assign(value.begin(), value.end());
}
inline
void Employee::setLastName(const bsl::string_view& value)
{
d_lastName.assign(value.begin(), value.end());
}
inline
void Employee::setId(int value)
{
d_id = value;
}
// ACCESSORS
inline
const bsl::string& Employee::firstName() const
{
return d_firstName;
}
inline
const bsl::string& Employee::lastName() const
{
return d_lastName;
}
inline
int Employee::id() const
{
return d_id;
}
BSLS_KEYWORD_CONSTEXPR const_iterator end() const BSLS_KEYWORD_NOEXCEPT
Return the past-the-end iterator for this view.
Definition bslstl_stringview.h:1620
BSLS_KEYWORD_CONSTEXPR const_iterator begin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_stringview.h:1602

Finally, we implement the free operators for Employee class:

inline
bool operator==(const Employee& lhs, const Employee& rhs)
{
return lhs.firstName() == rhs.firstName()
&& lhs.lastName() == rhs.lastName()
&& lhs.id() == rhs.id();
}
inline
bool operator!=(const Employee& lhs, const Employee& rhs)
{
return lhs.firstName() != rhs.firstName()
|| lhs.lastName() != rhs.lastName()
|| lhs.id() != rhs.id();
}

Example 3: A stream text replacement filter

In this example, we will utilize the string type and its associated utility functions to define a function that reads data from an input stream, replaces all occurrences of a specified text fragment with another text fragment, and writes the resulting text to an output stream.

First, we define the signature of the function, replace:

/// Read data from the specified `inputStream` and replace all
/// occurrences of the text contained in the specified `oldString` in
/// the stream with the text contained in the specified `newString`.
/// Write the modified data to the specified `outputStream`.
void replace(bsl::ostream& outputStream,
bsl::istream& inputStream,
const bsl::string& oldString,
const bsl::string& newString)

Then, we provide the implementation for replace:

{
const bsl::string::size_type oldStringSize = oldString.size();
const bsl::string::size_type newStringSize = newString.size();
bsl::getline(inputStream, line);
AllocatorTraits::size_type size_type
Definition bslstl_string.h:1303
std::basic_istream< CHAR_TYPE, CHAR_TRAITS > & getline(std::basic_istream< CHAR_TYPE, CHAR_TRAITS > &is, basic_string< CHAR_TYPE, CHAR_TRAITS, ALLOCATOR > &str, CHAR_TYPE delim)

Notice that we can use the getline free function defined in this component to read a single line of data from an input stream into a bsl::string.

if (!inputStream) {
return; // RETURN
}
do {

Next, we use the find function to search the contents of line for characters matching the contents of oldString:

int pos = line.find(oldString);
while (bsl::string::npos != pos) {

Now, we use the replace method to modify the contents of line matching oldString to newString:

line.replace(pos, oldStringSize, newString);
pos = line.find(oldString, pos + newStringSize);
basic_string & replace(size_type outPosition, size_type outNumChars, const basic_string &replacement)
Definition bslstl_string.h:6142

Notice that we provide find with the starting position from which to start searching.

}

Finally, we write the updated contents of line to the output stream:

outputStream << line;
bsl::getline(inputStream, line);
} while (inputStream);
}

Function Documentation

◆ bslstl_string_fill()

template<class CHAR_TYPE , class CHAR_TRAITS >
bool bslstl_string_fill ( std::basic_ostream< CHAR_TYPE, CHAR_TRAITS > &  os,
std::basic_streambuf< CHAR_TYPE, CHAR_TRAITS > *  buf,
std::size_t  n 
)