2.4. The string class

Like a byte string, a std::string is storage for a character sequence:

#include <string>        // access std::string functions

using std::string;       // alias type std::string to 'string'

int main() {
  string x;                          // empty string
  string greet =  "Hello, World!";   // create from C string
  string hello   ("Hello, World!");  // as above, constructor style syntax
  string howdy = {"Hello, World!"};  // C++11 only
  string howdy   {"Hello, World!"};  // as above, = is optional
  return 0;
}

What is different is that a std::string is a full-fledged object. It knows it’s own size, and comes with many convenience functions.

Notice that unlike a built-in variable declaration such as int x;, the declaration string x is not incomplete. The variable x is a complete and valid string object that stores no characters.

This tab shows alternate functions for accessing the first and last characters in a string.

The append function allows you to append N copies of a character or an array of characters to the end of a string.

The insert function allows you to insert 1 character or an array of characters at a position in a string.

Using the operator[] to access select characters in a string is, like an array, not range checked. This means that if you use an index referring to an invalid position, then your program might have undefined behavior, or fail unexpectedly. You can use the function at anywhere operator[] is allowed. The at function is range checked. While there is a cost associated with this check, if the index provided is out of range, then an std::out_of_range exception is thrown, which must be caught, otherwise the program will terminate.

if (a == b)
{
  b.at(0)  = 'H';   // might be OK
  b.at(-1) = 'W';   // never OK.  throws exception
}

Remember that a std::string is not a byte string. std::string is a class. A decision was made long ago that in order to remain more compatible with C, double quited strings should evaluate to byte strings. Declarations like this are a common source of confusion for new programmers:

auto my_string = "Howdy!";

What type is my_string?

This is one of those situations where auto may not be deducing the type you actually want. There are several simple ways to use auto and get the type deduced to be a std::string.

In C++14, you can simply append an s to the end of the string literal. This identifies the literal as type std::string.

auto my_string = "Howdy!"s;    // preferred

Alternatively, you can call the string constructor explicitly, which works for C++ versions older than C++14.

auto my_string = string("Howdy!");

auto your_str  = string{"Howdy!"};  // C++11 initialization syntax

Note

Look carefully at the size values printed for s1 and s2.

Are those sizes expected? Why or why not?

2.4.1. Getting information out of a string

A string knows its own size and can provide other useful information.

#include <cassert>
#include <string>
using std::string;
int main() {
  string my_string = "Hello";

  assert( my_string.size() == 5 );  // .length() is available also
  if (!my_string.empty()) {
    my_string += ", there.";       // my_string == "Hello, there."
  }
  return 0;
}

And the string class provides many functions dedicated to finding substrings within a string.

The simplest example is the find function.

Given any string object, for example, this string:

  auto us = "team"s;

defined using the C++14 string literal syntax, creates a new object us.

Once we have a string, calling the string member function find always returns a position:

  • Either a position within the string, or

  • The special value std::string::npos which means the value was not found in the string.

We can use this to check if we found what we were looking for:

  size_t pos = us.find('i');
  if(pos == std::string::npos) {
    std::cout << "There is no 'i' in 'team'\n";
  }

The position returned by find is a zero-based index into the string.

Find can also take a sequence of characters. In that case, it returns the position to the first char where the entire sequence is matched.

Reverse find

Similar to find, rfind performs the same task as find, but iterates through the string in reverse order: starting at the end and moving towards the first character. Keep in mind that the position returned is still based on the same index positions as regular find.

Find first of

The find_first_of function takes a char sequence, but unlike find where the entire sequence is used to find a match, find_first_of examines each character in the sequence, on at a time, and returns the minimum position of any of the characters listed as function arguments in the string. For example:

  auto hi = "Hello world"s;
  pos = hi.find_first_of("aeiou");      // pos == 1  (e)

The function returns the position of ‘e’ in ‘Hello world’, even though ‘e’ and ‘o’ are both present, because ‘e’ is first.

The order of the character arguments do not matter. The results would be exactly the same if the arguments were ‘uoiea’. Don’t take my word for it, try it yourself.

The special value std::string::npos is used both as an end of string indicator by functions that expect a string and as an indicator of not found by functions that return an index (like find).

2.4.2. Converting a std::string to a C string

You cannot use std::string in a function that expects const char* - you must convert it to a null terminated character array.

auto my_name = "Alice"s;


printf ("Hello again, %s\n", my_name);       // compile error!

// the c_str() function converts a string into a c string
printf ("Hello again, %s\n", my_name.c_str());

Self Check


More to Explore

You have attempted of activities on this page