C++ Logo

std-proposals

Advanced search

Re: [std-proposals] [Idea] Null-terminated string view (c_str_view / c_wstr_view) – a simpler alternative/complement to zstring_view

From: Peter Bindels <dascandy_at_[hidden]>
Date: Sun, 1 Feb 2026 10:42:08 +0100
> Advantages over P3655R2 “std::zstring_view”
> -------------------------------------------
> 1. Simpler, more minimal implementation – only two data members plus a
static empty buffer.

No, it's the same implementation.

> 2. Extremely low implementation burden – essentially just a thin wrapper
with a few constructors and accessors.

Same.

> 3. Direct, zero-cost construction from std::string – no runtime check
needed because std::string always guarantees null-termination.

Same. Except P3655 adds a (C++26 contracts) precondition check that there
are no embedded NULs.

> 4. Safe default constructor that points to a static null-terminated empty
buffer (never nullptr).

Same.

> 5. Runtime checks throw exceptions on violation – this follows modern
engineering best practices: fail fast and visibly in debug builds rather
than invoke undefined behavior.

No, because it uses C++26 contracts, not the 2010's best practices. See
also the feedback you got around many that do not want to have either UB or
exception throws at all. Not to mention that the thing you're modeling is
quite literally what DbC and contracts are.

> 6. Seamless round-trip with std::string_view via to_string_view() – users
can freely move between the null-terminated-guarantee view and the general
view with minimal code.

No, because string_view can never guarantee null-termination, so converting
back would lose the whole point of having a *type* that *guarantees* null
termination.

> 7. Clearer, more intuitive naming – “c_str_view” immediately conveys
“C-style string view” and matches the familiar .c_str() member function;
“zstring_view” is less obvious to many developers.

The paper was adjusted half a year ago to `cstring_view` based on four
different sources all giving a slight preference to `cstring_view` over
`zstring_view`. Note that "many developers" is a very vague statement,
there are also "many developers" that understood the zstring_view name
first, and had to be explained the cstring_view one.

> 8. Explicit wchar_t support with c_wstr_view – very helpful for Windows
developers who frequently need null-terminated wide strings.

Same, except P3655 also does u8, u16 and u32strings, because it is
orthogonal to that like basic_string_view and basic_string are as well.

> 9. Easy to teach and understand – the type does exactly what its name
suggests with no surprising corner cases.

Same.

> 10. No need for special “z” prefix that might confuse newcomers; aligns
better with existing standard library naming conventions (e.g., c_str(),
string_view).

Already changed, but also still arguable.

> 1. Is this design worth pursuing separately, or should effort be focused
on improving P3655 (zstring_view)?

I don't see enough difference to merit a separate paper; it seems to be a
reformulation of the same thing with a few minor differences that amount to
preference, where the existing paper has rationales for the approach it is
taking.

> 2. Are there any fatal flaws in the exception-throwing approach? (I chose
exceptions for safety, but could be convinced to switch to precondition
assertions or UB if the committee prefers.)

Yes. Adding UB is not something we want to get for a safety related type.
That completely defeats the point. Throwing exceptions does not work in
many code bases, and is something to be used for in-contract function calls
that very uncommonly fail anyway. This is not an in-contract call, this is
a precondition for the function. As such it should be a precondition, and
we do have those in C++26, so we should use them.

> 3. Naming preferences: c_str_view, ntbs_view, something else?

See discussion in P3655R3.

On Sun, Feb 1, 2026 at 10:19 AM FPE via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> To address the main objection (runtime cost of exceptions/checks), I've
>>> revised the design: checks and throws are now *only* in debug builds
>>> (#ifndef NDEBUG), similar to how many libraries use asserts for
>>> preconditions. In release builds, it's zero-overhead with precondition
>>> violations being UB – aligning more closely with string_view/span
>>> philosophy.
>>>
>>
This keeps debug-time safety (fail-fast on bad input) while preserving
>>> release performance.
>>>
>>> Questions:
>>> 1. Does this debug-only checking reduce the concerns about
>>> exceptions/performance?
>>>
>>
You're basically reimplementing c++26 contracts without using c++26
contracts. This will drop out when you change it to wording, as it will
then just read "precondition", making it basically identical.


> 2. Is relying on NDEBUG acceptable, or should we use something else (e.g.,
>>> contracts if available)?
>>>
>>
... probably starting to sound like a broken record at this point, but yes,
using the c++ features that we will have when this proposal merges seems
like a good idea - but also it will drop out in wording.


> 3. Still interested in merging ideas into P3655? (Happy to contribute
>>> naming, string ctor, etc.)
>>>
>>
Please let me know where in P3655 you would change something. The original
10 "Advantages over P3655R2 “std::zstring_view”" do not seem to have much
in common with what that paper actually says, not to mention that it is not
the most current version of the paper, being updated last in Oct-05-2025,
about 4 months ago. You can always find the latest published version on
https://wg21.link/p3655 .

The main difference I see is that P3655 suggests adding a full-fledged
string_view equivalent, allowing for a smooth transition from a code base
using `const std::string&` through cstring_view to string_view (if needed),
without bumping into functions that are suddenly absent on cstring_view.
Marco Foco did this change in his code base and has a good write-up on that
transition, in 7.3 NVIDIA Experience. If you want that to not be there,
please provide a rationale why that would be better - especially as that
does not have much, if any, runtime impact.

Best regards,
Peter Bindels

Received on 2026-02-01 09:42:22