std::string_view (std::basic_string_view<CharT>) is a lightweight, non-owning reference abstraction in <string_view> that encapsulates a pointer to a contiguous sequence of characters and a character length count. Standardized in C++17 and expanded in C++20 (starts_with, ends_with) and C++23 (contains), std::string_view unifies string parameters across C-style raw character arrays (const char*), owning string containers (std::string), and compile-time string constants ("literal"sv). It eliminates temporary dynamic heap allocations, enables .substr()), and serves as the standard read-only parameter type for modern C++ string APIs.
Prior to C++17, defining a function that accepted read-only string parameters forced developers into an architectural dilemma:
// Pre-C++17 Option 1: Const Reference to std::string
void process_log(const std::string& msg);
process_log("System Warning"); // DANGEROUS: Forces dynamic heap allocation for temporary std::string!
// Pre-C++17 Option 2: Raw C-Style Character Pointer
void process_log(const char* msg);
process_log("System Warning"); // FLAGGED: Loses length metadata, forcing O(N) strlen() scans!-
Forced Temporary Heap Allocations: Passing a C-style string literal (
"hello") to a function takingconst std::string&constructed a temporarystd::stringobject, executing a dynamic heap allocation (malloc/free) merely to read a constant array of bytes. -
Pervasive
$\mathcal{O}(N)$ strlenRe-scans: Passing rawconst char*pointers discarded length metadata, forcing every string function to re-scan character buffers sequentially to find the null-terminator. -
Expensive Substring Slicing: Calling
std::string::substr()allocated a brand-newstd::stringon the heap and copied the character bytes, making string parsers (JSON, XML, HTTP headers) allocation-heavy and slow.
Solution: C++17 introduced std::string_view, storing a pointer and an integer size in a 16-byte stack frame (sizeof(string_view) == 2 * sizeof(void*)), achieving zero-copy string borrowing.
std::string_view consists of exactly two scalar data members:
std::string_view Memory Representation (16 Bytes)
┌────────────────────────────────────────┬────────────────────────────────────────┐
│ const char* m_data │ std::size_t m_size │
├────────────────────────────────────────┼────────────────────────────────────────┤
│ 8-Byte Pointer to Character Sequence │ 8-Byte Character Count │
└──────────────────┬─────────────────────┴────────────────────────────────────────┘
│
▼
[ "a" | "v" | "a" | "n" | "t" | "-" | "g" | "a" | "r" | "d" | "e" ]
(Borrows existing memory; ZERO dynamic heap allocation!)
- Pass-By-Value Efficiency: Because
std::string_viewis small (16 bytes on 64-bit platforms), it fits directly into two 64-bit CPU registers. Always passstd::string_viewby value (void func(std::string_view sv)), rather than by reference (const std::string_view&).
-
Construction / Copying / Assignment:
$\mathcal{O}(1)$ constant time. -
Substring Slicing (
.substr(pos, count)):$\mathcal{O}(1)$ constant time. Slicing adjustsm_datapointer offset andm_sizeinteger without allocating memory or copying characters!
Null-Terminator Warning: Unlike C-strings (
const char*) orstd::string::c_str(), astd::string_viewis NOT guaranteed to be null-terminated (\0)!
std::string text = "Hello World";
std::string_view slice = std::string_view(text).substr(0, 5); // View over "Hello"
// DANGER: 'slice' is NOT null-terminated!
// slice.data()[5] points to ' ' (space), NOT '\0'!
// Passing slice.data() to C-APIs expecting null-terminated strings (printf, fopen)
// causes OUT-OF-BOUNDS MEMORY CORRUPTION!timeline
title std::string_view Evolution
C++17 : Introduced std::string_view in <string_view>
: Added "text"sv literal suffix in std::string_view_literals
: O(1) zero-copy substr() slicing
C++20 : Introduced std::u8string_view for UTF-8 char8_t
: Added .starts_with() and .ends_with() member methods
: Full constexpr conversion for all string_view member operations
C++23 : Added .contains() method for substring searching
C++26 : Native format and print formatting for string_view
│
▼
┌──────────────────────────────────────────────────────────────────┐ │ C++23 / C++26 │ ├──────────────────────────────────────────────────────────────────┤ │ • Added .contains() substring existence check in C++23 │ │ • Range / View construction overload (std::from_range) │ │ • Native formatting in std::format and std::print │ └──────────────────────────────────────────────────────────────────┘
---
## Comprehensive Code Examples
### Example 1: Zero-Allocation String Parameter Ingestion & $\mathcal{O}(1)$ Substring Slicing
Demonstrates `std::string_view` accepting C-strings, `std::string`, and string literals seamlessly.
```cpp
#include <iostream>
#include <string>
#include <string_view>
// Parameter accepts any string representation WITHOUT temporary heap allocations!
void parse_protocol_header(std::string_view header) {
std::cout << "Full Header: " << header << " | Length: " << header.size() << "\n";
// O(1) Zero-Copy Substring Slicing
std::string_view prefix = header.substr(0, 4); // Views "HTTP"
std::cout << "Protocol Prefix: " << prefix << " (Zero-copy slice!)\n";
}
int main() {
using namespace std::string_view_literals;
// 1. Pass string literal directly (NO std::string allocation!)
parse_protocol_header("HTTP/1.1 200 OK");
// 2. Pass owning std::string
std::string dynamic_header = "HTTP/2.0 404 NOT_FOUND";
parse_protocol_header(dynamic_header);
// 3. Pass C++17 string_view literal ("..."sv)
parse_protocol_header("HTTP/3.0 500 ERROR"sv);
return 0;
}
Demonstrates expressive string inspections added in C++20 and C++23.
#include <iostream>
#include <string_view>
void inspect_url(std::string_view url) {
// C++20 starts_with and ends_with
if (url.starts_with("https://")) {
std::cout << "Secure HTTPS Connection Detected.\n";
}
if (url.ends_with(".png") || url.ends_with(".jpg")) {
std::cout << "Image Resource URL Detected.\n";
}
// C++23 contains method
#if defined(__cpp_lib_string_view_contains) && __cpp_lib_string_view_contains >= 202011L
if (url.contains("api/v1")) {
std::cout << "API Version 1 Endpoint Detected.\n";
}
#endif
}
int main() {
inspect_url("https://example.com/api/v1/avatar.png");
return 0;
}Demonstrates a critical bug: creating a string_view referencing a temporary std::string that goes out of scope.
#include <iostream>
#include <string>
#include <string_view>
std::string_view create_dangling_view() {
std::string temporary_str = "Temporary Data Buffer";
// DANGEROUS BUG: Returning a string_view referencing local variable 'temporary_str'!
return temporary_str;
} // 'temporary_str' is DESTROYED HERE! Returned string_view points to FREED MEMORY!
int main() {
std::string_view dangling = create_dangling_view();
// DANGEROUS UNDEFINED BEHAVIOR: Dereferencing dangling pointer!
// std::cout << dangling << "\n"; // CRASH / Memory Corruption!
std::cout << "Dangling string_view hazard demonstrated.\n";
return 0;
}-
Pass
std::string_viewBy Value:- Write
void process(std::string_view sv), notvoid process(const std::string_view& sv). Becausestd::string_viewis 16 bytes, passing by value allows compilers to pass it inside CPU registers.
- Write
-
CRITICAL: Lifetime Invariant Management:
std::string_viewis a non-owning view. It does not manage the lifespan of the underlying character array.- Rule: Never store a
std::string_viewin a long-lived class data member or return astd::string_viewfrom a function unless you guarantee that the referenced string storage outlives the view.
-
Interoperability with C APIs:
- Never pass
sv.data()directly to C functions expecting null-terminated C-strings (fopen,printf,strlen) unless you know the view covers an entire null-terminated buffer. - Fix: If a null-terminated string is required, construct an explicit
std::string:std::string null_terminated_str(sv); c_api_function(null_terminated_str.c_str());
- Never pass
- Related to:
std::string— Owning string container.std::span(C++20) — Contiguous non-owning view over arbitrary element arrays (std::span<T>).std::format/std::print(C++20/C++23) — Native formatting support for string views.- Raw String Literals — Unescaped string input for string views.
- Superseded by: None.
- Supersedes:
const std::string¶meters for read-only string APIs and rawconst char*pointer passing.
Back to C++17 section.