将 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_view
s 都应该是 NUL 终止的。和std::string
一样,NUL 字符不是字符串大小的一部分,而是那里。
我发现它对于处理 C 接口非常有用。
【讨论】:
我只是做了同样的事情,我同意界面非常好,并且消除了将 const std::string& 作为参数的最后一个原因。使用私有继承(例如比较和转换回 string_view)确实会失去很多便利 - 查看界面,似乎唯一有问题的突变器是 remove_***fix 和 swap - 我只是重新实现了 swap,并添加了 remove_ ***修复为私有非实现成员,一切似乎都正常 - 所以你确实可以从 std::string_view 公开继承。唯一的问题是将来会向 string_view 添加新的突变体。 虽然可以说是不好的风格。此外,您在将 zstring_views 传递给采用 string_view& 的函数时会遇到问题(这在两种以上的情况下很奇怪......) 为方便起见,@Shaggizstring_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_string
和c_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` 是不是安全?