假设我们在类中有一个简单的getter方法,该方法返回const对std::string成员的引用:
const std::string& getString() const noexcept { return someString; }
Run Code Online (Sandbox Code Playgroud)
随着std::string_viewC ++ 17 的问世,我想知道编写它是否具有任何优势:
const std::string_view getString() const noexcept { return someString; }
Run Code Online (Sandbox Code Playgroud)
一种方法比另一种方法有优点/缺点吗?显然(如果我错了,请纠正我),两种解决方案肯定会比这更好:
const char* getString() const noexcept { return someString.c_str(); }
Run Code Online (Sandbox Code Playgroud)
我已经看到了这个相关的问题,但是我要的是稍微不同的东西。
我正在编写许多 string_view 擅长的解析器代码,并且已经开始喜欢这种类型。我最近读了 ArthurO'Dwyer 的文章std::string_view is aborrow type,他的结论是 string_view (和其他“借用类型”)可以使用,只要它们“...仅作为函数参数和 for 循环出现”控制变量。” (有几个例外)。
但是,我最近开始使用 string_view 作为将枚举转换为字符串(我经常使用)的函数的返回值,例如这个Compiler Explorer:
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
enum class Color
{
red, green, blue, yellow,
last // Must be kept last
};
constexpr std::string_view toString(Color color);
// The rest would normally be in a .cpp file
using cts = std::pair<Color, std::string_view>;
constexpr std::array colorNames = {cts{Color::red, "red color"},
cts{Color::green, "green color"},
cts{Color::blue, "blue color"},
cts{Color::yellow, "yellow color"}};
static_assert(colorNames.size() …Run Code Online (Sandbox Code Playgroud) 我只是遇到了一些误解:至少在libc ++实现中,std :: experimental :: string_view具有以下简洁的实现:
template <class _CharT, class _Traits....>
class basic_string_view {
public:
typedef _CharT value_type;
...
template <class _Allocator>
basic_string_view(const basic_string<_CharT, _Traits, _Allocator>& str):
__data(str.data()), __size(str.size())
{
}
private:
const value_type* __data;
size_type __size;
};
Run Code Online (Sandbox Code Playgroud)
这个实现是否意味着如果我们将rvalue表达式传递给这个构造函数,在构造之后使用__data时我们会得到未定义的行为?
在实现C++ 1z std::basic_string_view以在较旧的编译器上使用它时,我遇到了流输出操作符重载的问题.基本上,它必须输出string_viewwhile 引用的内容而不依赖于任何存在的null-terminator(因为string_view不保证是以null终止的).
通常,编写重载operator<<非常容易,因为您可以依赖已经存在的重载,因此不需要使用SO中此问题中提到的 sentry对象.
但在这种情况下,没有预定义的重载来operator<<获取字符指针和长度(显然).因此,我std::string在当前的实现中创建了一个临时实例:
template< typename TChar, typename TTraits >
auto operator<<(::std::basic_ostream<TChar, TTraits>& p_os, basic_string_view<TChar, TTraits> p_v)
-> ::std::basic_ostream<TChar, TTraits>&
{
p_os << p_v.to_string(); // to_string() returns a ::std::string.
return p_os;
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但我真的不喜欢我必须创建一个临时std::string实例的事实,因为这需要冗余地复制数据和动态内存的潜在用法.至少在我看来,这违背了使用轻量级引用类型的目的.
所以我的问题是:
在没有开销的情况下为string_view实现正确格式化输出的最佳方法是什么?
在研究时,我发现LLVM是这样的:(在这里找到)
// [string.view.io]
template<class _CharT, class _Traits>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, basic_string_view<_CharT, _Traits> __sv)
{
return _VSTD::__put_character_sequence(__os, …Run Code Online (Sandbox Code Playgroud) 假设您有一个std::unordered_set<std::string>.
您有一个std::string_view要在容器中搜索的对象。问题是,您不想std::string从您的 中创建 a std::string_view,因为这种首先违背了使用的目的std::string_view。
不过,好像std::string_view应该可以作为key使用;应该有某种方式来比较std::string_viewand std::string,因为它们基本上代表同一件事。但是没有,无论如何都没有在 STL 中。
这是一个僵局,我是否被迫编写自己的比较对象std::string_view并std::string与我的对象一起使用std::unordered_set?
编辑:这个问题特定于 string_view 对象。“重复”问题不相关。正如预期的那样,我收到了一个独特问题的独特答案。
我一直std::string_view在一些旧代码中添加 s 来表示配置参数等字符串,因为它提供了只读视图,由于不需要复制,速度更快。
string_view但是,由于operator+未定义,因此无法将两个连接在一起。我看到这个问题有几个答案表明它是一个疏忽,并且有一个建议添加它。但是,这是添加 astring和 a string_view,大概如果实现的话,生成的串联将是std::string
添加两个string_view也属于同一类别吗?如果不是,为什么不string_view支持添加两个?
样本
std::string_view s1{"concate"};
std::string_view s2{"nate"};
std::string_view s3{s1 + s2};
Run Code Online (Sandbox Code Playgroud)
这是错误
error: no match for 'operator+' (operand types are 'std::string_view' {aka 'std::basic_string_view<char>'} and 'std::string_view' {aka 'std::basic_string_view<char>'})
Run Code Online (Sandbox Code Playgroud) 我知道,琐碎小事std::string_view不能保证会以null结尾。但是,我不知道std::string_view文字是否保证为空终止。
例如:
#include <string_view>
using namespace std::literals;
int main()
{
auto my_sv = "hello"sv;
}
Run Code Online (Sandbox Code Playgroud)
C ++ 17或更高版本是否保证以my_sv.data()Null结尾?
===以下为更新===
以下全部来自n4820:
- 根据5.13.5.14,字符串文字是空终止的。
- 根据5.13.8,用户定义的字符串字面量由字符串文字和自定义后缀组成。说,
"hello"sv,hello是字符串文字,sv是后缀。- 按照5.13.8.5,
"hello"sv作为表单的一个呼叫被处理operator "" sv(str, len);为每5.13.5.14,str是空终止。- 按照21.4.2.1,
sv的data()必须返回str。
他们可以证明"hello"sv.data()C ++标准保证它可以为空终止吗?
boost中的string_ref和GSL中的string_span都没有定义带有一对迭代器的构造函数.这个决定的原因是什么?
通常这不是什么大问题,我可以像这样创建string_ref:
boost::string_ref s(start, std::distance(start, finish));
Run Code Online (Sandbox Code Playgroud)
但我希望构造函数采用一对迭代器的原因是因为我的代码看起来像这样:
template<typename Type, typename Iterator>
void func(const Iterator& begin, const Iterator& end)
{
Type s(begin, end);
//do stuff with s
}
Run Code Online (Sandbox Code Playgroud)
目前,我可以这样称呼它:
func<std::string>(start, finish)
Run Code Online (Sandbox Code Playgroud)
我想将其更改为:
func<boost::string_ref>(start, finish) //compile error
Run Code Online (Sandbox Code Playgroud)
但是该代码将无法编译,因为缺少构造函数在string_ref中使用一对迭代器
虽然 aspan可以从范围构造,string_view但不能从字符范围构造。
因此,例如,需要以下代码:
// assume chars_span is a span of chars
std::cout << std::string_view(chars_span.data(), chars_span.size());
// or:
std::cout << std::string_view(chars_span.begin(), chars_span.end());
Run Code Online (Sandbox Code Playgroud)
而不是不支持的更简单的范围语法:
std::cout << std::string_view(chars_span);
Run Code Online (Sandbox Code Playgroud)
是否有理由没有string_view接受一系列字符的构造函数,或者它只是被忽视或被认为不够重要?
我正在解析二进制网络数据,我希望使该过程尽可能减少分配。但现在我意识到有两个非常相似的概念可能都足够适合我的情况,它们是std::basic_string_view<T>和std::span<T>。
所以我想知道。这两者之间有什么区别?使用其中一种比另一种有什么优势?一个明显的区别是可用性,std::basic_string_viewC++17 中已存在,而std::spanC++20 中已存在(但您可以使用“指南支持库”中的旧标准)。但还有别的事吗?应该如此,否则它们就不会同时进入标准。
c++ ×10
string-view ×10
c++17 ×6
string ×3
c++11 ×1
c++20 ×1
standards ×1
stl ×1
string-span ×1