Coming Soon
This lesson is currently being developed
Introduction to std::string_view
Learn to work with text strings using the standard library.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
5.8 — Introduction to std::string_view
In this lesson, you'll learn about std::string_view
, a lightweight way to work with string data that doesn't own the memory. You'll understand when to use it, how it differs from std::string
, and why it can improve performance.
What is std::string_view?
std::string_view
is a lightweight, non-owning reference to a sequence of characters. Introduced in C++17, it provides a way to view string data without creating copies or managing memory.
Think of std::string_view
as a window that lets you look at string data that exists somewhere else - it doesn't own the data, but it can read and analyze it efficiently.
Key differences: std::string vs std::string_view
Feature | std::string | std::string_view |
---|---|---|
Memory ownership | Owns its data | Views existing data |
Memory allocation | May allocate memory | No allocation |
Modification | Can modify content | Read-only view |
Copying cost | Expensive (copies data) | Cheap (copies view) |
Lifetime | Manages its own lifetime | Depends on viewed data |
Including std::string_view
std::string_view
requires C++17 and the <string_view>
header:
#include <iostream>
#include <string_view>
#include <string>
int main()
{
std::string_view message = "Hello, World!";
std::cout << message << std::endl;
return 0;
}
Output:
Hello, World!
Creating std::string_view objects
From string literals
#include <iostream>
#include <string_view>
int main()
{
// Create string_view from string literals
std::string_view greeting = "Hello";
std::string_view message = "Welcome to C++!";
std::cout << "Greeting: " << greeting << std::endl;
std::cout << "Message: " << message << std::endl;
std::cout << "Greeting length: " << greeting.length() << std::endl;
std::cout << "Message length: " << message.length() << std::endl;
return 0;
}
Output:
Greeting: Hello
Message: Welcome to C++!
Greeting length: 5
Message length: 15
From std::string objects
#include <iostream>
#include <string_view>
#include <string>
int main()
{
std::string str = "Programming in C++";
std::string_view view = str; // Create view from string
std::cout << "Original string: " << str << std::endl;
std::cout << "String view: " << view << std::endl;
// Both refer to the same data
std::cout << "Same data? " << (view.data() == str.data()) << std::endl;
return 0;
}
Output:
Original string: Programming in C++
String view: Programming in C++
Same data? 1
From character arrays
#include <iostream>
#include <string_view>
int main()
{
char buffer[] = "Hello, World!";
std::string_view view(buffer);
std::cout << "Buffer: " << buffer << std::endl;
std::cout << "View: " << view << std::endl;
std::cout << "View length: " << view.length() << std::endl;
// Create partial view
std::string_view partial(buffer, 5); // First 5 characters
std::cout << "Partial view: " << partial << std::endl;
return 0;
}
Output:
Buffer: Hello, World!
View: Hello, World!
View length: 13
Partial view: Hello
Basic string_view operations
Accessing characters
#include <iostream>
#include <string_view>
int main()
{
std::string_view text = "Programming";
std::cout << "Text: " << text << std::endl;
std::cout << "First character: " << text[0] << std::endl;
std::cout << "Last character: " << text[text.length() - 1] << std::endl;
std::cout << "Third character: " << text.at(2) << std::endl;
// Front and back methods
std::cout << "Front: " << text.front() << std::endl;
std::cout << "Back: " << text.back() << std::endl;
// Print all characters
std::cout << "All characters: ";
for (size_t i = 0; i < text.length(); ++i)
{
std::cout << text[i] << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Text: Programming
First character: P
Last character: g
Third character: o
Front: P
Back: g
All characters: P r o g r a m m i n g
Size and empty checks
#include <iostream>
#include <string_view>
int main()
{
std::string_view empty;
std::string_view text = "Hello, World!";
std::cout << "Empty view:" << std::endl;
std::cout << " Content: '" << empty << "'" << std::endl;
std::cout << " Length: " << empty.length() << std::endl;
std::cout << " Size: " << empty.size() << std::endl;
std::cout << " Empty: " << empty.empty() << std::endl;
std::cout << "\nText view:" << std::endl;
std::cout << " Content: " << text << std::endl;
std::cout << " Length: " << text.length() << std::endl;
std::cout << " Size: " << text.size() << std::endl;
std::cout << " Empty: " << text.empty() << std::endl;
return 0;
}
Output:
Empty view:
Content: ''
Length: 0
Size: 0
Empty: 1
Text view:
Content: Hello, World!
Length: 13
Size: 13
Empty: 0
Substring operations
#include <iostream>
#include <string_view>
int main()
{
std::string_view text = "The quick brown fox";
std::cout << "Original: " << text << std::endl;
// Extract substrings using substr()
std::string_view first_word = text.substr(0, 3); // "The"
std::string_view second_word = text.substr(4, 5); // "quick"
std::string_view from_brown = text.substr(10); // "brown fox"
std::cout << "First word: " << first_word << std::endl;
std::cout << "Second word: " << second_word << std::endl;
std::cout << "From 'brown': " << from_brown << std::endl;
// Remove prefix and suffix
std::string_view no_prefix = text;
no_prefix.remove_prefix(4); // Remove "The "
std::cout << "After removing prefix: " << no_prefix << std::endl;
std::string_view no_suffix = no_prefix;
no_suffix.remove_suffix(4); // Remove " fox"
std::cout << "After removing suffix: " << no_suffix << std::endl;
return 0;
}
Output:
Original: The quick brown fox
First word: The
Second word: quick
From 'brown': brown fox
After removing prefix: quick brown fox
After removing suffix: quick brown
Finding and searching
#include <iostream>
#include <string_view>
int main()
{
std::string_view text = "The quick brown fox jumps over the lazy dog";
std::cout << "Text: " << text << std::endl;
// Find substrings
size_t pos1 = text.find("fox");
size_t pos2 = text.find("cat");
size_t pos3 = text.find("the"); // First occurrence
size_t pos4 = text.find("the", 32); // Starting from position 32
std::cout << "Position of 'fox': ";
if (pos1 != std::string_view::npos)
std::cout << pos1 << std::endl;
else
std::cout << "not found" << std::endl;
std::cout << "Position of 'cat': ";
if (pos2 != std::string_view::npos)
std::cout << pos2 << std::endl;
else
std::cout << "not found" << std::endl;
std::cout << "First 'the' at: " << pos3 << std::endl;
std::cout << "Next 'the' after pos 32: " << pos4 << std::endl;
// Find characters
size_t char_pos = text.find('q');
std::cout << "First 'q' at position: " << char_pos << std::endl;
// Find first/last of character sets
size_t vowel_pos = text.find_first_of("aeiou");
size_t consonant_pos = text.find_first_not_of("The ");
std::cout << "First vowel at: " << vowel_pos << std::endl;
std::cout << "First non-'The ' character at: " << consonant_pos << std::endl;
return 0;
}
Output:
Text: The quick brown fox jumps over the lazy dog
Position of 'fox': 16
Position of 'cat': not found
First 'the' at: 0
Next 'the' after pos 32: 31
First 'q' at position: 4
First vowel at: 2
First non-'The ' character at: 4
Comparing string_views
#include <iostream>
#include <string_view>
#include <string>
int main()
{
std::string_view view1 = "apple";
std::string_view view2 = "banana";
std::string_view view3 = "apple";
std::cout << "view1: " << view1 << std::endl;
std::cout << "view2: " << view2 << std::endl;
std::cout << "view3: " << view3 << std::endl;
// Equality comparisons
std::cout << "\nEquality:" << std::endl;
std::cout << "view1 == view2: " << (view1 == view2) << std::endl;
std::cout << "view1 == view3: " << (view1 == view3) << std::endl;
std::cout << "view1 != view2: " << (view1 != view2) << std::endl;
// Lexicographic comparisons
std::cout << "\nLexicographic:" << std::endl;
std::cout << "view1 < view2: " << (view1 < view2) << std::endl;
std::cout << "view2 > view1: " << (view2 > view1) << std::endl;
// Compare with string literals
std::cout << "\nWith literals:" << std::endl;
std::cout << "view1 == \"apple\": " << (view1 == "apple") << std::endl;
// Compare with std::string
std::string str = "apple";
std::cout << "view1 == str: " << (view1 == str) << std::endl;
return 0;
}
Output:
view1: apple
view2: banana
view3: apple
Equality:
view1 == view2: 0
view1 == view3: 1
view1 != view2: 1
Lexicographic:
view1 < view2: 1
view2 > view1: 1
With literals:
view1 == "apple": 1
view1 == str: 1
Performance benefits
Function parameters
Using string_view
as function parameters can improve performance by avoiding unnecessary copies:
#include <iostream>
#include <string_view>
#include <string>
// Function using string_view (efficient)
void printStringInfo(std::string_view text)
{
std::cout << "Text: " << text << std::endl;
std::cout << "Length: " << text.length() << std::endl;
std::cout << "First char: " << text.front() << std::endl;
std::cout << "Last char: " << text.back() << std::endl;
}
// Function using const string& (still efficient, but less flexible)
void printStringInfoRef(const std::string& text)
{
std::cout << "Text (ref): " << text << std::endl;
std::cout << "Length: " << text.length() << std::endl;
}
int main()
{
std::string str = "Hello, World!";
const char* cstr = "Hello, C++!";
std::cout << "Using string_view parameter:" << std::endl;
printStringInfo(str); // Works with std::string
printStringInfo(cstr); // Works with C-string
printStringInfo("Literal"); // Works with string literal
std::cout << "\nUsing const string& parameter:" << std::endl;
printStringInfoRef(str); // Works with std::string
// printStringInfoRef(cstr); // Would create temporary std::string
// printStringInfoRef("Literal"); // Would create temporary std::string
return 0;
}
Output:
Using string_view parameter:
Text: Hello, World!
Length: 13
First char: H
Last char: !
Text: Hello, C++!
Length: 11
First char: H
Last char: !
Text: Literal
Length: 7
First char: L
Last char: l
Using const string& parameter:
Text (ref): Hello, World!
Length: 13
Avoiding unnecessary copies
#include <iostream>
#include <string_view>
#include <string>
// Function that processes string data without modifying it
std::string_view getFileExtension(std::string_view filename)
{
size_t dot_pos = filename.find_last_of('.');
if (dot_pos != std::string_view::npos)
{
return filename.substr(dot_pos + 1); // Return view of extension
}
return {}; // Empty string_view if no extension
}
std::string_view getFilename(std::string_view path)
{
size_t slash_pos = path.find_last_of("/\\");
if (slash_pos != std::string_view::npos)
{
return path.substr(slash_pos + 1);
}
return path; // No path separators found
}
int main()
{
std::string filepath = "/home/user/documents/report.txt";
std::cout << "Full path: " << filepath << std::endl;
std::string_view filename = getFilename(filepath);
std::string_view extension = getFileExtension(filename);
std::cout << "Filename: " << filename << std::endl;
std::cout << "Extension: " << extension << std::endl;
// These operations are efficient - no string copying involved!
return 0;
}
Output:
Full path: /home/user/documents/report.txt
Filename: report.txt
Extension: txt
Common use cases
Text parsing
#include <iostream>
#include <string_view>
#include <vector>
// Simple word splitter using string_view
std::vector<std::string_view> splitWords(std::string_view text)
{
std::vector<std::string_view> words;
size_t start = 0;
while (start < text.length())
{
// Skip whitespace
while (start < text.length() && text[start] == ' ')
++start;
if (start >= text.length())
break;
// Find end of word
size_t end = start;
while (end < text.length() && text[end] != ' ')
++end;
// Add word to vector
words.push_back(text.substr(start, end - start));
start = end;
}
return words;
}
int main()
{
std::string text = "The quick brown fox jumps";
std::cout << "Original text: " << text << std::endl;
std::vector<std::string_view> words = splitWords(text);
std::cout << "Words (" << words.size() << "):" << std::endl;
for (size_t i = 0; i < words.size(); ++i)
{
std::cout << " " << i + 1 << ": '" << words[i] << "'" << std::endl;
}
return 0;
}
Output:
Original text: The quick brown fox jumps
Words (5):
1: 'The'
2: 'quick'
3: 'brown'
4: 'fox'
5: 'jumps'
Configuration parsing
#include <iostream>
#include <string_view>
struct ConfigValue
{
std::string_view key;
std::string_view value;
};
ConfigValue parseConfigLine(std::string_view line)
{
// Find the '=' separator
size_t equals_pos = line.find('=');
if (equals_pos == std::string_view::npos)
{
return {"", ""}; // Invalid line
}
std::string_view key = line.substr(0, equals_pos);
std::string_view value = line.substr(equals_pos + 1);
// Trim whitespace (simplified)
while (!key.empty() && key.back() == ' ')
key.remove_suffix(1);
while (!value.empty() && value.front() == ' ')
value.remove_prefix(1);
return {key, value};
}
int main()
{
std::string config_data =
"username=john_doe\n"
"password=secret123\n"
"port=8080\n"
"debug=true\n";
std::cout << "Configuration data:" << std::endl;
std::cout << config_data << std::endl;
// Parse each line
std::string_view data_view = config_data;
size_t pos = 0;
while (pos < data_view.length())
{
size_t newline = data_view.find('\n', pos);
if (newline == std::string_view::npos)
newline = data_view.length();
std::string_view line = data_view.substr(pos, newline - pos);
ConfigValue config = parseConfigLine(line);
if (!config.key.empty())
{
std::cout << "Key: '" << config.key
<< "', Value: '" << config.value << "'" << std::endl;
}
pos = newline + 1;
}
return 0;
}
Output:
Configuration data:
username=john_doe
password=secret123
port=8080
debug=true
Key: 'username', Value: 'john_doe'
Key: 'password', Value: 'secret123'
Key: 'port', Value: '8080'
Key: 'debug', Value: 'true'
Important considerations
Lifetime management
Be careful about the lifetime of the data that string_view
references:
#include <iostream>
#include <string_view>
#include <string>
std::string_view dangerousFunction()
{
std::string local = "This is dangerous!";
return local; // ❌ DANGER: Returning view to local variable
// The string will be destroyed when function ends
}
std::string_view safeFunction()
{
return "This is safe"; // ✅ SAFE: String literal has static lifetime
}
int main()
{
std::string_view safe_view = safeFunction();
std::cout << "Safe view: " << safe_view << std::endl;
// Be careful with this pattern:
std::string_view dangerous_view = dangerousFunction();
// Using dangerous_view here is undefined behavior!
return 0;
}
Read-only nature
Remember that string_view
is read-only:
#include <iostream>
#include <string_view>
int main()
{
std::string_view text = "Hello, World!";
std::cout << "Original: " << text << std::endl;
// These operations are read-only and safe:
std::cout << "Length: " << text.length() << std::endl;
std::cout << "First char: " << text[0] << std::endl;
std::cout << "Substring: " << text.substr(0, 5) << std::endl;
// This would not compile - string_view is read-only:
// text[0] = 'h'; // ❌ Error: cannot modify through string_view
return 0;
}
Summary
std::string_view
is a powerful tool for efficient string handling:
- Lightweight: No memory allocation, just a view of existing data
- Efficient: Avoids unnecessary string copies
- Flexible: Works with string literals,
std::string
, and character arrays - Read-only: Provides a non-modifying view of string data
- C++17 feature: Requires modern C++ compiler support
Key benefits:
- Better performance when passing strings to functions
- Efficient substring operations
- Unified interface for different string types
- Zero-copy string operations
Important considerations:
- Be careful about lifetime of viewed data
- Read-only access only
- Requires C++17 or later
std::string_view
is particularly useful for function parameters, parsing operations, and any situation where you need to examine string data without modifying it.
Quiz
- What C++ standard introduced
std::string_view
? - What's the main advantage of
string_view
overstd::string
for function parameters? - Can you modify the content of a string through a
string_view
? - What happens if you create a
string_view
from a localstd::string
and return it from a function? - What's the difference between
remove_prefix()
andsubstr()
for getting a substring?
Practice exercises
Try these string_view exercises:
- Write a function that takes a
string_view
and counts the number of words in it - Create a simple CSV parser using
string_view
that splits a line into fields - Write a function that checks if a filename (passed as
string_view
) has a specific extension - Implement a simple text trimming function that removes leading and trailing whitespace using
string_view
operations
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions