2016-08-19 68 views
10

我从新的C++ 17标准中发现string_view有点多余。为什么使用string_view而不是泛化的container_view <T>?

我们有一个相当详细的passing data to callee简单机制的集合,没有太多的开销,现在又有另外一个只针对一个容器类型。

我不明白为什么提供这种机器只适用于字符串,而不是一些更通用的类型的其他容器。一个明智的答案是我们已经有了这些解决方案。例如在C++17 and beyond演示文稿中,string_view被解释为observer_ptr<T> (or T*) for string

请对比更一般的container_view来说明参数,而不是C++ 17引入的string_view。

+3

我认为'observer_ptr'比较只会产生混淆,并且会影响是否应该有一个广义的'container_view'而不是特定的'string_view'的问题。 – juanchopanza

+2

因为对字符串的操作是最常见的编程任务?我认为答案很简单。 –

+0

container_view不会在一个'const char *'上工作,但'string_view'有额外的假设,即这样的一个指针指向一个*字符串*,当它由该单指针构造时以'\ 0'结尾构造函数。 –

回答

9

广义container_view被更恰当地称为范围。我们有一个完全用于范围概念的TS航路。

现在,我们有string_view作为一个单独的类型,因为它有一个专门的字符串专用接口,以匹配basic_string的字符串专用接口。或者至少,匹配常量/非分配接口。

请注意,container_view或任何您称之为的东西将无法删除与生成它的容器的连接。或者至少,不是每个访问/操作都不支付类型擦除开销。

相比之下,string_view是基于const char*和整数。那个班级并不关心这个字符串来自哪里;它提供了一个连续的角色阵列的视图,无论谁拥有它。它可以这样做,因为它知道源是一个连续的数组,因此使用指针作为其迭代器的核心。

你不能为任意容器做到这一点。你的container_view<vector>会有不同的迭代器,从container_view<list>或其他什么。它会必须。这意味着如果你以container_view作为函数参数,你必须选择一个特定的容器来使用(强制用户准确提供该容器类型),使你的函数成为一个模板,或者使用一个类型擦除的迭代器范围比较慢)。

对于GSL类型spanstring_span,也有后C++ 17提案。前者表示(可能是多维的)连续阵列的可修改“视图”。后者代表连续字符串的可修改“视图”。

3

string_view提供了不止一个简单的字符串指针。你需要把它看作不仅仅是一个简单的非拥有指针:如果这就是它的全部,string_view不允许你“切分”字符串的一部分,并对其应用操作(虽然仍然是一个视图;因此不招致的拷贝的成本):

char *s = "welcome to stackoverflow"; 
auto s = std::string_view{s + 8, 2}; // a view on "to" 
// you can then apply many operations on this view, that wouldn't make sense more on your general non_owning<T>: 
s.remove_prefix(std::min(s.find_first_not_of(" "), s.size())); 
// it also "inherits" (copies the API) a lot directly from std::basic_string 
auto view2 = s.substr(3, 4); // a generic non-owning ptr would copy here, instead of giving you a new view 
+0

有没有让我们无法为其他容器提供“视图”的相同行为的东西? – tomekpe

+1

不是。这就是为什么Boost有'array_view'(和boost.fusion另一种类型的过滤器,地图等视图)。唯一的问题是你需要手动完成,因为正如我在这里演示的那样,每个容器都需要特定的行为。 – Ven

+1

@tomekpe另外还有几个竞争性的提议,将一个通用范围视图包含到标准中(甚至是一个称为“span”的可变范围视图,如同Microsoft GSL中提供的那样)。这些建议可能需要在供应商开始实施之前达成设计协议。 – Morwenn

相关问题