Date: Wed, 4 Feb 2026 01:42:36 -0500
On Tue, Feb 3, 2026 at 11:10 PM FPE via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>>>
>>> Hi Jason (and everyone),
>>>
>>> Thanks for the great question about what makes this "modern C++"!
>>>
>>> In my view, the key is consolidating related data into a single, self-contained type – just like `std::string_view` did for (ptr, len) pairs. Passing one parameter (a `cstring_view`) instead of two (const char* + size_t) reduces boilerplate and makes interfaces cleaner and less error-prone. It's the same philosophy that led to `string_view`, `span`, ranges, etc.: encapsulate common patterns into dedicated types for better expressiveness and safety.
>>>
>>> To illustrate the trade-offs more concretely:
>>>
>>> - **cstring_view vs raw (ptr + len)**: 1 parameter vs 2 – simpler, more readable function signatures.
>>> - **cstring_view vs raw ptr**: Avoids repeated `strlen` calls (0 vs potentially n times in deep call chains, especially when mixing WinAPI calls with direct string ops like memcpy/logging).
>>> - **cstring_view vs std::string**: No allocation (0 vs 1 heap allocation) – crucial for performance-critical code.
>>> - **cstring_view vs std::string_view**: Safe for direct C API/WinAPI use (guaranteed null-termination) vs risk of UB (if the view is a trimmed/split substring without trailing '\0').
>>>
>>> A real-world scenario where `cstring_view` shines (and feels very "modern"):
>>>
>>> I'm writing a performance-sensitive library (e.g., parsing/protocol handling) where I receive a raw `char*` buffer. I need high throughput, so:
>>>
>>> - I can't afford `std::string` (unnecessary allocation – same reason `string_view` exists).
>>> - Raw (ptr + len) is too verbose (every function takes two params).
>>> - Raw ptr alone forces repeated `strlen` on deep call stacks (hurts perf when chaining logging, DB saves, and WinAPI calls).
>>> - `std::string_view` isn't safe if sub-views (trim/split) lose the trailing '\0' – risking UB in lower-level WinAPI/printf calls.
>>>
>>> Here, `cstring_view` is the sweet spot: one parameter, cached length for fast access, guaranteed null-termination for safe C interop, and zero-cost internally (since the library controls construction and won't "attack itself" with bad lengths or malicious embedded nulls).
>>>
>>> Does this scenario make sense to you as a solid modern C++ use case? Or am I overlooking better options?
I think you may be missing the point of contention, at least the part
I'm talking about.
I don't really care if `cstring_view` carries a redundant size
parameter internally. What I care about is that, if there is a size
parameter, it *must* match what `strlen` would return in all cases.
That is, if the string that `cstring_view` was given contains embedded
NUL characters, the view will act like a string that terminates on the
first NUL character.
Because that's how C strings work.
The use case you outline doesn't involve embedded NULs, and your use
of "safe C interop" seems to suggest that your code would fail to work
if the given string contained embedded NULs. So this is not the
problem that is under discussion here.
<std-proposals_at_[hidden]> wrote:
>>>
>>> Hi Jason (and everyone),
>>>
>>> Thanks for the great question about what makes this "modern C++"!
>>>
>>> In my view, the key is consolidating related data into a single, self-contained type – just like `std::string_view` did for (ptr, len) pairs. Passing one parameter (a `cstring_view`) instead of two (const char* + size_t) reduces boilerplate and makes interfaces cleaner and less error-prone. It's the same philosophy that led to `string_view`, `span`, ranges, etc.: encapsulate common patterns into dedicated types for better expressiveness and safety.
>>>
>>> To illustrate the trade-offs more concretely:
>>>
>>> - **cstring_view vs raw (ptr + len)**: 1 parameter vs 2 – simpler, more readable function signatures.
>>> - **cstring_view vs raw ptr**: Avoids repeated `strlen` calls (0 vs potentially n times in deep call chains, especially when mixing WinAPI calls with direct string ops like memcpy/logging).
>>> - **cstring_view vs std::string**: No allocation (0 vs 1 heap allocation) – crucial for performance-critical code.
>>> - **cstring_view vs std::string_view**: Safe for direct C API/WinAPI use (guaranteed null-termination) vs risk of UB (if the view is a trimmed/split substring without trailing '\0').
>>>
>>> A real-world scenario where `cstring_view` shines (and feels very "modern"):
>>>
>>> I'm writing a performance-sensitive library (e.g., parsing/protocol handling) where I receive a raw `char*` buffer. I need high throughput, so:
>>>
>>> - I can't afford `std::string` (unnecessary allocation – same reason `string_view` exists).
>>> - Raw (ptr + len) is too verbose (every function takes two params).
>>> - Raw ptr alone forces repeated `strlen` on deep call stacks (hurts perf when chaining logging, DB saves, and WinAPI calls).
>>> - `std::string_view` isn't safe if sub-views (trim/split) lose the trailing '\0' – risking UB in lower-level WinAPI/printf calls.
>>>
>>> Here, `cstring_view` is the sweet spot: one parameter, cached length for fast access, guaranteed null-termination for safe C interop, and zero-cost internally (since the library controls construction and won't "attack itself" with bad lengths or malicious embedded nulls).
>>>
>>> Does this scenario make sense to you as a solid modern C++ use case? Or am I overlooking better options?
I think you may be missing the point of contention, at least the part
I'm talking about.
I don't really care if `cstring_view` carries a redundant size
parameter internally. What I care about is that, if there is a size
parameter, it *must* match what `strlen` would return in all cases.
That is, if the string that `cstring_view` was given contains embedded
NUL characters, the view will act like a string that terminates on the
first NUL character.
Because that's how C strings work.
The use case you outline doesn't involve embedded NULs, and your use
of "safe C interop" seems to suggest that your code would fail to work
if the given string contained embedded NULs. So this is not the
problem that is under discussion here.
Received on 2026-02-04 06:42:51
