C++ 在C API中使用gsl::zstring_视图

C++ 在C API中使用gsl::zstring_视图,c++,string-view,cpp-core-guidelines,guideline-support-library,string-span,C++,String View,Cpp Core Guidelines,Guideline Support Library,String Span,我正在尝试使用现代的字符串处理方法(如or)与C API(DBus)交互,该API将字符串作为以null结尾的const char*s,例如 DBusMessage* dbus_message_new_method_call( const char* destination, const char* path, const char* iface, const char* method ) string\u view和string\u span不保证它

我正在尝试使用现代的字符串处理方法(如or)与C API(DBus)交互,该API将字符串作为以null结尾的
const char*
s,例如

DBusMessage* dbus_message_new_method_call(
    const char* destination,
    const char* path,
    const char* iface,
    const char* method 
    )
string\u view
string\u span
不保证它们的内容以null结尾-因为span是
(char*start,ptrdiff\t length)
对,这在很大程度上是关键。但GSL还提供了一个
zstring_视图
,它保证以null结尾。周围的
zstring_span
表明它的设计完全是为了处理遗留API和C API,但我一开始使用它就遇到了几个问题:

  • 将字符串文字表示为
    string\u span
    很简单:

    cstring_span<> bar = "easy peasy";
    
    这使得声明更加嘈杂,而且文字(保证以null结尾)不能隐式转换为
    zstring\u span
    ,这似乎也很奇怪
    确保_z()
    字符串span
    的构造函数和转换不同,也不是
    constexpr

  • std::string
    也有类似的奇怪之处,它可以隐式转换为
    string\u span
    ,但不能转换为
    zstring\u span
    ,即使
    std::string::data()。同样,您必须调用
    确保_z()

    zstring_span to_zspan(std::string&s){return sure_z(s)}
    
  • 似乎存在一些常量正确性问题。上述方法可行,但是

    czstring_span<> to_czspan(const std::string& s) { return ensure_z(s); }
    
    czstring_span to_czspan(const std::string&s){return sure_z(s)}
    
    编译失败,错误是无法从
    span
    转换为
    span

  • 这一点比其他点小,但是返回
    char*
    (您可以将其馈送到像DBus这样的C API)的成员函数称为
    aspect_z()
    。当
    zstring\u span的构造函数

  • 如果
    zstring_span
    被设计为“将以零结尾的跨距转换为传统的字符串”,为什么它在这里的使用看起来如此繁琐?我是不是误用了?有什么东西我忽略了吗?

    它之所以“笨重”,部分是因为它是有意忽略的

    这:

    zstring_span to_zspan(std::string&s){return sure_z(s)}
    
    这不是一个安全的操作。为什么?因为虽然
    s
    确实以NUL结尾,但实际的
    s
    完全可能包含内部NUL字符。这是你可以用
    std::string
    做的合法的事情,但是
    zstring\u span
    任何人都无法处理。他们将截断字符串

    相反,从这个角度来看,
    string\u span/view
    转换是安全的。这类字符串的使用者使用大小相同的字符串,因此可以处理嵌入式NUL

    因为
    zstring_span
    转换是不安全的,所以应该有一些明确的标记,表明正在进行一些可能不安全的操作<代码>确保_z
    表示该显式符号

    另一个问题是C++没有机制来区分文字字符串参数和任何旧的代码> const char */COD>或<代码> const char []/COD>参数。由于裸

    常量char*
    可能是也可能不是字符串文字,因此必须假设它不是,因此使用更详细的转换

    C++中的字符串文字也可以包含嵌入的NUL字符,因此适用上述推理。

    const
    问题似乎是一个代码错误,您可能应该将其归档

  • 一个文本(保证以null结尾)不能隐式转换为
    zstring\u span
  • 字符串文字的类型为
    常量字符[…]
    。类型中没有信息表明此
    const char
    数组是以null结尾的字符串。下面是一些具有相同类型的其他代码,但没有空终止,其中
    确保_z
    将快速失败

    const char foo_arr[4]{ 'o', 'd', 'd', '-' };
    ensure_z(foo_arr);
    
    “foo”
    foo_arr
    都属于
    const char[4]
    类型,但只有字符串文字以null结尾,而
    foo_arr
    则不是

    请注意,
    sure_z
    czstring_span
    的组合可以编译,但不起作用<代码>确保_z
    只返回字符串,不返回终止的空字节。当您将其传递给
    czstring\u span
    构造函数时,构造函数将无法搜索空字节(该字节被
    sure\u z
    截断)

    您需要将字符串文字转换为跨度,并将其传递给构造函数:

    czstring_span<> foo = ensure_span("odd");
    
    你应该考虑在GSL回购协议中提交一个问题,使各阶层保持一致。我不确定隐式转换是否是个好主意,因此我更喜欢在
    zstring\u span
    中如何进行隐式转换,而不是
    string\u span
    如何进行隐式转换

  • 似乎存在一些常量正确性问题
  • 在这里,我的第一个想法是
    czstring\u span to_czspan(const std::string&s){return czstring\u span{s};}
    编译了,但不起作用。另一个解决方案是一个新函数
    sure_cz
    ,它返回
    span
    。你应该考虑提交一个问题。

  • 假设_z()
  • empty()
    的存在和
    中的代码as\u string\u span()
    表明类应该能够处理空字符串跨度。在这种情况下,
    由于_string_span
    总是返回字符串而不终止空字节,
    确保_z
    将返回带有终止空字节的字符串,如果为空则失败,
    假设_z
    将假设
    !empty()
    并返回带有终止空字节的字符串

    但是唯一的构造函数使用非空的字符跨度,因此
    empty()
    永远不能zstring_span<> to_zspan(std::string& s) { return ensure_z(s); }
    const char foo_arr[4]{ 'o', 'd', 'd', '-' };
    ensure_z(foo_arr);
    
    czstring_span<> foo = ensure_span("odd");
    
    zstring_span<> to_zspan(std::string& s) { return zstring_span<>{s}; }