【问题标题】:How you convert a std::string_view to a const char*?如何将 std::string_view 转换为 const char*?
【发布时间】:2018-01-03 16:34:15
【问题描述】:

使用带有-std=c++17标志的gcc-7.1编译,以下程序会引发错误:

#include <string_view>
void foo(const char* cstr) {}
void bar(std::string_view str){
    foo(str);
}

错误信息是

In function 'void bar(std::string_view)':
error: cannot convert 'std::string_view {aka std::basic_string_view<char>}' to 'const char*' for argument '1' to 'void foo(const char*)'
 foo(str);

我很惊讶没有转换为 const char*,因为其他库(abseil、bde)提供了类似的 string_view 类,它们隐式转换为 const char*

【问题讨论】:

标签: c++ string c++17 string-view


【解决方案1】:

std::string_view 不提供到const char* 的转换,因为它不存储以空值结尾的字符串。它基本上存储了指向第一个元素的指针和字符串的长度。这意味着您不能将它传递给期望以空字符结尾的字符串的函数,例如期望const char*foo(否则您将如何获得大小?),因此决定它不是值得。

如果您确定您的视图中有一个以空字符结尾的字符串,您可以使用std::string_view::data

如果你不是,你应该重新考虑首先使用std::string_view 是否是一个好主意,因为如果你想要一个有保证的以空结尾的字符串std::string 是你想要的。对于单行,您可以使用std::string(object).data()注意:返回值指向一个临时 std::string 实例,该实例将在表达式结束后被销毁! )。

【讨论】:

  • 为什么 std::string_view 不提供转换的解释很好,但只提供了对问题的临时答案。
  • 您对std::string(object).data() 的建议很糟糕,因为在大多数情况下,数据将指向未分配的存储空间。
  • @rems4e 当我看到std::string(object).data() 推荐时,我也发出了警报,但没有重要的警告是返回的指针指向临时 std::string 对象内的数据,该对象仅持续到最大的封闭表达式的结尾。
  • 请从答案中删除std::string(object).data() 或提供一个容易看到的警告。这里的std::string(object) 被释放,因此生成的C 字符串是未定义的。我已经看到这个 sn-p 被粘贴在整个互联网和各种代码库中。这个答案造成了巨大的损失。
  • 非常可悲的是,在堆栈溢出时,我们非常担心那些追随货物崇拜到 T 并从堆栈溢出中复制粘贴而不是使用大脑的白痴。我不明白,这怎么值得考虑?您要么需要将一个临时字符串传递给某个函数,该函数将对其执行一些操作,要么您不需要。鉴于这个问题,这是完全可以接受的。为什么有人要关心一些白痴是否不能盲目地阅读和复制他甚至不理解的东西?这种白痴首先不应该有工作,不会被SO答案屏蔽。
【解决方案2】:

只需执行std::string(string_view_object).c_str() 即可获得保证为空终止的临时副本(并在行尾清理它)。

这是必需的,因为字符串视图不保证空终止。例如,您可以查看较长缓冲区的中间。

如果这个用例很昂贵并且您已经证明它是一个瓶颈,您可以编写一个增强的string_view 来跟踪它是否为空终止(基本上,如果它是从原始char const* 构造的)。

然后你可以编写一个辅助类型来接受这个增强的string_view 并将其复制到std::string 或直接存储增强的string_view,并有一个隐式转换为char const*,它返回正确的以 null 结尾的缓冲区。

然后在您的代码库中的任何地方使用该增强的帮助器类型,而不是 string_view,这可能还会增加字符串视图与 std 字符串的交互,以捕捉您的视图到达 std 字符串缓冲区末尾的情况。

但实际上,这可能是矫枉过正。

一种更好的方法可能是将采用const char* 的API 重写为采用string_view

【讨论】:

  • by "(并在行尾清理它)。",我可以继续使用该 Rvalue 的成员直到 std::string(string_view_object).c_str() 坐的范围结束,对吧?
  • @sandthorn 不,直到完整表达式结束,而不是范围。
  • @sandthorn 如果你想让字符串一直存在,你可能更喜欢std::string TempVar(string_view_object);,然后在你需要它的范围内,TempVar.c_str()
【解决方案3】:

您可以拨打foo(std::string(str).c_str())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 2016-09-12
    相关资源
    最近更新 更多