Date: Mon, 2 Feb 2026 16:00:04 +0800
Thank you all for the continued feedback – especially Jan Schultke for the
detailed comparisons, Thiago Macieira for raising the important security
concerns, and Ville Voutilainen for the broader perspective!
I completely agree that solving this pain point (safe, efficient interop
with C/WinAPI) is more important than whose design wins. I'd love to see
std::cstring_view (or equivalent) in the standard as soon as possible,
ideally for C++29 – regardless of whether it builds on my ideas or the
current P3655R3. The demand is clearly there.
A few thoughts in response:
1. Progress: What has been the main blocker for P3655/cstring_view so far?
>From the revisions, it seems more about design consensus (naming,
invariants, etc.) than implementation complexity – is that accurate?
2. On simplicity: My minimal c_str_view was motivated exactly because if we
want a lightweight type, avoiding code duplication from string_view is key.
One way to achieve this is making it a subtype inheriting from string_view
(hiding/override data() if needed, adding c_str() for clearer semantics).
Since a null-terminated view is always a valid string_view (but not vice
versa), inheritance fits naturally – with no space overhead. Alternatively,
keeping it independent with to_string_view() also avoids duplication.
Either way seems fine to me.
3. On exceptions/checks: I still believe a one-size-fits-all noexcept/UB
approach might not suit everyone. Some projects have zero tolerance for UB
and prefer fail-fast (e.g., via exceptions or asserts in debug). Perhaps an
optional macro (e.g., HAVE_C_STR_VIEW_EXCEPTION, default off) or contracts
could accommodate this without forcing it on performance-critical code?
4. On Thiago Macieira's security concerns (embedded nulls): Great points –
these are real risks in untrusted input scenarios. However, going back to
string_view's original goals: it accelerates code by trusting input
(avoiding repeated strlen) and consolidating (ptr, len) into one object.
Similar trust applies here: if constructing with wrong length {txt, 100}
on "asdf", string_view bugs out too – but internally, libraries can safely
pass c_str_view around for speed:
void func1(std::c_str_view cv)
{
...
HANDLE handle = CreateFileA(cv.c_str(), ...);
...
}
//--------------------------------------------------
void func2(std::c_str_view cv)
{
size_t len = cv.size();
// do something (use cv.size() for Log/DataBase/...)
func1(cv);
}
//--------------------------------------------------
void func3(std::c_str_view cv)
{
size_t len = cv.size();
// do something (use cv.size() for Log/DataBase/...)
func2(cv);
}
Using string_view would risk UB at CreateFileA. Recomputing length on
every construction would reintroduce repeated strlen (performance hit on
deep call chains). For untrusted/external input, validating once at the
boundary (bottom-layer function) makes more engineering sense than
per-construction – libraries don't usually "attack themselves".
What do you think about these trade-offs? Happy to revise further (e.g.,
attached updated debug-only version) or contribute directly to
P3655/cstring_view (naming, inheritance idea, optional checks, etc.). Barry
Revzin (or current author) – any interest?
Thanks again!
Best,
FPE(foxofice)
Peter Bindels <dascandy_at_[hidden]> 于2026年2月1日周日 17:42写道:
>
> > 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
>
detailed comparisons, Thiago Macieira for raising the important security
concerns, and Ville Voutilainen for the broader perspective!
I completely agree that solving this pain point (safe, efficient interop
with C/WinAPI) is more important than whose design wins. I'd love to see
std::cstring_view (or equivalent) in the standard as soon as possible,
ideally for C++29 – regardless of whether it builds on my ideas or the
current P3655R3. The demand is clearly there.
A few thoughts in response:
1. Progress: What has been the main blocker for P3655/cstring_view so far?
>From the revisions, it seems more about design consensus (naming,
invariants, etc.) than implementation complexity – is that accurate?
2. On simplicity: My minimal c_str_view was motivated exactly because if we
want a lightweight type, avoiding code duplication from string_view is key.
One way to achieve this is making it a subtype inheriting from string_view
(hiding/override data() if needed, adding c_str() for clearer semantics).
Since a null-terminated view is always a valid string_view (but not vice
versa), inheritance fits naturally – with no space overhead. Alternatively,
keeping it independent with to_string_view() also avoids duplication.
Either way seems fine to me.
3. On exceptions/checks: I still believe a one-size-fits-all noexcept/UB
approach might not suit everyone. Some projects have zero tolerance for UB
and prefer fail-fast (e.g., via exceptions or asserts in debug). Perhaps an
optional macro (e.g., HAVE_C_STR_VIEW_EXCEPTION, default off) or contracts
could accommodate this without forcing it on performance-critical code?
4. On Thiago Macieira's security concerns (embedded nulls): Great points –
these are real risks in untrusted input scenarios. However, going back to
string_view's original goals: it accelerates code by trusting input
(avoiding repeated strlen) and consolidating (ptr, len) into one object.
Similar trust applies here: if constructing with wrong length {txt, 100}
on "asdf", string_view bugs out too – but internally, libraries can safely
pass c_str_view around for speed:
void func1(std::c_str_view cv)
{
...
HANDLE handle = CreateFileA(cv.c_str(), ...);
...
}
//--------------------------------------------------
void func2(std::c_str_view cv)
{
size_t len = cv.size();
// do something (use cv.size() for Log/DataBase/...)
func1(cv);
}
//--------------------------------------------------
void func3(std::c_str_view cv)
{
size_t len = cv.size();
// do something (use cv.size() for Log/DataBase/...)
func2(cv);
}
Using string_view would risk UB at CreateFileA. Recomputing length on
every construction would reintroduce repeated strlen (performance hit on
deep call chains). For untrusted/external input, validating once at the
boundary (bottom-layer function) makes more engineering sense than
per-construction – libraries don't usually "attack themselves".
What do you think about these trade-offs? Happy to revise further (e.g.,
attached updated debug-only version) or contribute directly to
P3655/cstring_view (naming, inheritance idea, optional checks, etc.). Barry
Revzin (or current author) – any interest?
Thanks again!
Best,
FPE(foxofice)
Peter Bindels <dascandy_at_[hidden]> 于2026年2月1日周日 17:42写道:
>
> > 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-02 08:00:21
