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: Jan Schultke <janschultke_at_[hidden]>
Date: Sun, 1 Feb 2026 06:30:43 +0100
It seems like you are mainly making this proposal in response to P3655R3,
but the latest revision is
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3655r3.html

See also
https://github.com/cplusplus/papers/issues/2285#issuecomment-2993041542 for
feedback that LEWG already gave on the proposal. This is very important.

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

> Hello everyone,
>
> I would like to propose a null-terminated string view type for the
> standard library to ease interoperability with C APIs and WinAPI, where
> std::string_view does not guarantee null-termination.
>
> Motivation
> ----------
> std::basic_string_view does not guarantee null-termination, which makes
> direct use with C functions and WinAPI either unsafe (risk of buffer
> overrun) or forces unnecessary copies to std::string. A dedicated view type
> that *guarantees* null-termination would eliminate this friction without
> sacrificing performance.
>
> There is already an active proposal P3655R2 “std::zstring_view” that
> addresses exactly this problem. However, I believe the design below offers
> several advantages that make it worth considering either as a complement or
> as a simpler alternative.
>
> Proposed design
> ---------------
> #include <string_view>
> #include <string>
> #include <stdexcept>
>
> namespace std
> {
>
> template <typename T>
> class basic_c_str_view
> {
> public:
> // Constructor
> inline basic_c_str_view()
> {
> m_data = m_s_empty_buffer;
> m_size = 0;
> }
> //--------------------------------------------------
> inline basic_c_str_view(const T *txt)
> {
> if(txt == nullptr) [[unlikely]]
> throw runtime_error("txt must not be nullptr");
>
> m_data = txt;
> m_size = char_traits<T>::length(txt);
> }
> //--------------------------------------------------
> inline basic_c_str_view(const T *txt, size_t size)
> {
> if(txt[size] != (T)'\0') [[unlikely]]
> throw runtime_error("txt is not null-terminated");
>
> m_data = txt;
> m_size = size;
> }
> //--------------------------------------------------
> inline basic_c_str_view(basic_string_view<T> sv)
> {
> if(sv.data()[sv.size()] != (T)'\0') [[unlikely]]
> throw runtime_error("sv is not null-terminated");
>
> m_data = sv.data();
> m_size = sv.size();
> }
> //--------------------------------------------------
> inline basic_c_str_view(const basic_string<T> &str)
> {
> m_data = str.data();
> m_size = str.size();
> }
>
> inline bool empty() const noexcept { return m_size == 0; }
> inline const T* c_str() const noexcept { return m_data; }
> inline size_t size() const noexcept { return m_size; }
> inline basic_string_view<T> to_string_view() noexcept { return { m_data,
> m_size }; }
>
> protected:
> const T *m_data;
> size_t m_size;
>
> private:
> static inline const T m_s_empty_buffer[1] = { (T)'\0' };
> };
>
> using c_str_view = basic_c_str_view<char>;
> using c_wstr_view = basic_c_str_view<wchar_t>;
>
> } // namespace std
>
>
> Advantages over P3655R2 “std::zstring_view”
> -------------------------------------------
> 1. Simpler, more minimal implementation – only two data members plus a
> static empty buffer.
> 2. Extremely low implementation burden – essentially just a thin wrapper
> with a few constructors and accessors.
> 3. Direct, zero-cost construction from std::string – no runtime check
> needed because std::string always guarantees null-termination.
> 4. Safe default constructor that points to a static null-terminated empty
> buffer (never nullptr).
> 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.
> 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.
> 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.
> 8. Explicit wchar_t support with c_wstr_view – very helpful for Windows
> developers who frequently need null-terminated wide strings.
> 9. Easy to teach and understand – the type does exactly what its name
> suggests with no surprising corner cases.
> 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).
>
> I believe these qualities make the type easier to adopt, easier to
> implement correctly, and less controversial to add to the standard.
>
> Questions for the community
> ---------------------------
> 1. Is this design worth pursuing separately, or should effort be focused
> on improving P3655 (zstring_view)?
> 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.)
> 3. Naming preferences: c_str_view, ntbs_view, something else?
> 4. Any other suggested changes or additional features?
>
> I’m happy to revise the design based on feedback and, if the consensus is
> to merge ideas, contribute to the existing zstring_view effort.
>
> Thank you for your time and any comments!
>
> Best regards,
> FPE(foxofice)
>
> foxofice.fpe_at_[hidden]
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2026-02-01 05:31:01