2016-08-19 35 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

相關問題