使用指標差異在基于范圍的 for 回圈中查找元素的索引是否有效?
這里提出了許多關于將索引和基于范圍的回圈一起使用的問題,但他們幾乎都說如果您還需要元素的索引,則不要使用基于范圍的回圈。但似乎,至少std::vector,std::array和其他容器,是連續的記憶體,你可以使用指標的差異,找到元素的索引,提供你回圈訪問元素的參考。例如:
// Prints the indices of all elements for which Foo::bar is true.
void Example(const std::vector<Foo>& v) {
for (const auto& e : v) {
if (e.bar()) {
auto index = &e - v.data(); // Valid???
std::cout << index << std::endl;
}
}
}
上面的代碼可以正確編譯和運行,但我不能完全確定它的有效性。有沒有語言律師可以確認或否認這是否是一種可以接受的查找元素索引的方法?
此外,假設一個容器有一個data()成員,那么它的元素在記憶體中是連續的,因此可以安全地使用這種方法嗎?
uj5u.com熱心網友回復:
如果底層迭代器滿足 LegacyContiguousIterator (C 17) 的要求,則是。此要求表明*(itr n)等效于*(addressof(*itr) n)。
這是來自https://en.cppreference.com/w/cpp/named_req/ContiguousIterator
C 20 將其替換為contiguous_iterator概念。
Cppreference 頁面表示vector<bool>不符合上述概念,但所有其他向量都符合。string、string_view、array 和 valarray 的開始/結束多載的迭代器也是如此。
uj5u.com熱心網友回復:
auto index = &e - v.data(); // Valid???
除非Foo是 的別名bool,是的。
&e并v.data()具有指標型別,[expr.add]/5適用:
當兩個指標運算式
P和Q相減時,結果的型別是實作定義的有符號整數型別;此型別應std?::?ptrdiff_-t與<cstddef>標題 ([support.types.layout]) 中定義的型別相同。(5.2) 否則,如果
P和Q分別指向陣列元素i和j同一個陣列物件x,則運算式P - Q的值為i?j。
因此,除非e或v.data()不是同一陣列物件的一部分,否則這是明確定義的。如果Foo是 的別名bool,則可能發生這種情況,否則每個vector.overview/2確保滿足此條件[container.requirements.general],本身確保[iterator.concept.contiguous]/2:
讓我們
a和b被提領迭代器和c具有型別的非可提領迭代I,從而b從可達a并且c是可到達b,并讓D是iter_-difference_-t<I>。該型I車型contiguous_迭代器只有當(2.2)
to_-address(b) == to_-address(a) D(b - a)和
(2.3)to_-address(c) == to_-address(a) D(c - a)。
此外,假設一個容器有一個 data() 成員,那么它的元素在記憶體中是連續的,因此使用這種方法是安全的嗎?
我們可以構建不安全的奇怪情況,但除非你做一些非常奇特的事情,否則你是安全的!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/388761.html
上一篇:如何使用openMP使此代碼執行緒安全?蒙特卡羅二維積分
下一篇:基類是派生類的歧義基類
