![](/img/trans.png)
[英]Is there an std view for random access iterators, as std::span is for contiguous iterators?
[英]Are view iterators valid beyond the lifetime of the view?
假設我有一個自定義容器 class 將數據存儲在 map 中:
class Container
{
public:
void add(int key, std::string value) { _data.emplace(key, std::move(value)); }
private:
std::map<int, std::string> _data;
};
我想提供一個接口來訪問 map 的值(不是鍵)。 范圍庫提供std::views::values
給我一個地圖值的范圍:
auto values() { return std::views::values(_data); }
用法:
Container c;
c.add(1, "a");
c.add(3, "b");
c.add(2, "c");
for (auto &value : c.values())
std::cout << value << " "; // Prints "a c b"
但是因為我想把我的 class 當作一個容器,我想要begin()
和end()
迭代器。 我可以這樣做嗎?
auto begin() { return std::ranges::begin(values()); }
auto end() { return std::ranges::end(values()); }
在這里,我調用values()
來獲取地圖值的范圍,並將迭代器獲取到范圍的開頭(或哨兵結束迭代器)。 但范圍本身超出 scope 並被破壞。 迭代器本身是否仍然有效?
從這個例子中,似乎迭代器是有效的。 但是標准是否保證了這一點,無論是針對std::views:values
還是針對一般視圖?
視圖迭代器在視圖的生命周期之后是否有效?
這里的屬性稱為借用范圍。 如果一個范圍是一個借用范圍,那么即使一個范圍被破壞,它的迭代器仍然有效。 R&
,如果R
是一個范圍,是最簡單的借用范圍 - 因為它不是迭代器將被綁定到的引用的生命周期。 還有其他幾個熟悉的借用范圍——比如span
和string_view
。
有條件借用了一些范圍適配器( P2017 )。 也就是說,他們不會在他們正在適應的范圍之上添加任何額外的 state - 因此,如果基礎范圍是(或基礎范圍是),則可以借用適應的范圍。 例如,只要借用r
,就會借用views::reverse(r)
。 但是views::split(r, pat)
不是有條件地借用的——因為模式存儲在適配器本身而不是迭代器中(假設它也可以存儲在迭代器中,但要付出代價)。
views::values(r)
就是一個例子:當r
被借用時,它就是一個借用范圍。 而且,在您的示例中,基礎范圍是ref_view
,它本身總是被借來的(與R&
總是被借用的原理相同)。
注意這里:
auto begin() { return std::ranges::begin(values()); }
auto end() { return std::ranges::end(values()); }
將右值范圍傳遞給ranges::begin
僅在借用范圍時才有效。 那是[range.access.begin]/2.1 :
如果
E
是右值並且enable_borrowed_range<remove_cv_t<T>>
為false
,則ranges::begin(E)
格式錯誤。
所以因為你的原始代碼編譯過,你可以確定它是有效的。
C++20 標准承認范圍類型的概念,其迭代器可以比該范圍類型的特定 object 壽命更長。 這稱為“借用范圍”。 該標准定義了幾種借用范圍的類型(通過提供ranges::enable_borrowed_range
的特化): subrange
、 span
、 string_view
和其他幾個。
但是,沒有其他標准庫類型具有該變量的特化。 所以這些類型不是借來的范圍。
std::views::elements_view
(其中values_view
是其別名)不是借用范圍。 因此,您不能假設超出范圍的迭代器仍然有效。
即使它是一個借用的范圍,比較來自不同范圍的迭代器/哨兵(甚至是同一范圍的同一視圖的不同實例)也永遠無效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.