将 std::string_view 与 api 一起使用,期望以 null 终止的字符串

Posted

技术标签:

【中文标题】将 std::string_view 与 api 一起使用,期望以 null 终止的字符串【英文标题】:Using std::string_view with api, what expects null terminated string 【发布时间】:2016-12-22 15:46:04 【问题描述】:

我有一个采用std::string_view 并使用函数的方法,该函数将空终止字符串作为参数。例如:

void stringFunc(std::experimental::string_view str) 
    some_c_library_func(/* Expects null terminated string */);

问题是,处理这种情况的正确方法是什么? str.to_string().c_str() 是唯一的选择吗?而且我真的很想在这个方法中使用std::string_view,因为我在其中传递了不同类型的字符串。

【问题讨论】:

【参考方案1】:

我通过创建一个名为zstring_view 的备用string_view 类解决了这个问题。它是从string_view 私下继承的,并包含它的大部分接口。

主要区别在于zstring_view 不能从string_view 创建。此外,任何会从末尾删除元素的 string_view API 都不是接口的一部分,或者它们返回 string_view 而不是 zstring_view

它们可以从任何以 NUL 结尾的字符串源创建:std::string 等等。我什至为它们创建了特殊的用户定义文字后缀:_zsv

这个想法是,只要您不手动将非 NUL 终止的字符串放入 zstring_view,所有 zstring_views 都应该是 NUL 终止的。和std::string 一样,NUL 字符不是字符串大小的一部分,而是那里

我发现它对于处理 C 接口非常有用。

【讨论】:

我只是做了同样的事情,我同意界面非常好,并且消除了将 const std::string& 作为参数的最后一个原因。使用私有继承(例如比较和转换回 string_view)确实会失去很多便利 - 查看界面,似乎唯一有问题的突变器是 remove_***fix 和 swap - 我只是重新实现了 swap,并添加了 remove_ ***修复为私有非实现成员,一切似乎都正常——所以你确实可以从 std::string_view 公开继承。唯一的问题是将来会向 string_view 添加新的突变体。 虽然可以说是不好的风格。此外,您在将 zstring_views 传递给采用 string_view& 的函数时会遇到问题(这在两个以上的方面很奇怪......) @Shaggi zstring_view 允许隐式衰减到 string_view 是非常安全的,为方便起见。需要注意的是逆序。 同意,但是如果您是公开派生的,则在将 zstring_view 传递给采用 string_view& 的函数时不会发生转换,从而使其不安全。【参考方案2】:

您不能通过std::string_view 更改字符串。因此,您不能添加终止 '\0' 字符。因此,您需要将字符串复制到其他地方以添加'\0'-terminator。如果字符串足够短,您可以通过将字符串放在堆栈上来避免堆分配。如果您知道 std::string_view 是一个以 null 结尾的字符串的一部分,那么您可以检查结尾之后的字符是否是 '\0' 字符,并在这种情况下避免复制。除此之外,我没有看到更多的优化空间。

【讨论】:

很好用 VLA。 @user1095108 但是任何允许在 C++ 中使用 VLA 的编译器都在应用非标准扩展,所以我想说 VLA 永远不会很好。 :P 通过 alloca 实际上到处都支持它们,你可以让它们便携【参考方案3】:

您当然不应该在std::experimental::string_view 上致电data

与 basic_string::data() 和字符串字面量不同,data() 可能返回一个 指向非空终止缓冲区的指针。

因此请致电to_stringc_str

void stringFunc(std::experimental::string_view str) 
    some_c_library_func(str.to_string().c_str());

或:

void stringFunc(std::experimental::string_view str) 
    std::string real_str(str);
    some_c_library_func(real_str.c_str());

【讨论】:

string::data() 返回一个指向原始字符串的指针,它不一定以空值结尾。如果你想要一个以 null 结尾的字符串,请使用 string::c_str() @HowardLeeHarkness 自 C++11 以来,它必须以空值终止的。参见例如cplusplus.com/reference/string/string/data【参考方案4】:

在某些情况下,C 类型函数具有重载,它们接受字符串的长度作为单独的参数。

例如而不是使用strcasesmp() 值得切​​换到strncasecmp()。 当然,在这种特殊情况下,如果字符串不相等,但前 n 个字符相等,则需要实现额外的逻辑。

但它可能是为字符串视图编写自定义类的好选择。

【讨论】:

以上是关于将 std::string_view 与 api 一起使用,期望以 null 终止的字符串的主要内容,如果未能解决你的问题,请参考以下文章

将 std::string_view 传递给执行 const std::string& 的 API

如何将 boost::string_view 转换为 std::string_view?

哈希<std::string> 与哈希<std::string_view>

将函数参数 `const char*` 转换为 `std::string_view` 是不是安全?

将 std::string 的 xvalue 传递给采用 std::string_view 的函数

文件到 std::string_view