簡體   English   中英

對迭代器的鉗位是否有效

[英]Is clamping on iterators valid

我在實際生產代碼中發現了以下內容。 我懷疑它實際上具有未定義的行為,但是,我在 cppreference 上找不到相關信息。 您能否確認這是 UB 或有效代碼以及為什么這是 UB/有效(最好帶有標准的引用)?

#include <vector>

int main(int, char **)
{
    auto v = std::vector<int>({1,2,3,4,5});
    auto begin = v.begin();
    auto outOfRange = begin + 10;
    auto end = v.end();
    auto clamped = std::min(outOfRange, end);
    return (clamped == end) ? 0 : 42;
}

編譯器資源管理器上的代碼

如您所見, begin + 10將創建一個超出std::vector范圍的迭代器。 但是,沒有使用該迭代器,因為它是使用std::min鉗制的。

對於隨機訪問迭代器, operator+(n)的操作語義是[random.access.iterators],表 99 *:

 difference_type m = n; if (m >= 0) while (m--) ++r; else while (m++) --r; return r;

對於++r ,前提條件是[input.iterators],表 95 *:

前提條件: r是可取消引用的。

使用begin() + n如果n大於容器的大小,則從m的某個值開始將不滿足此先決條件。 begin + 10; 你已經有UB了,和代碼的rest無關。

GCC 標准庫清理程序(使用-D_GLIBCXX_DEBUG編譯)會給您以下錯誤:

/usr/include/c++/10/debug/safe_iterator.h:885:
In function:
    __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, 
    std::__cxx1998::vector<int, std::allocator<int> > >, 
    std::__debug::vector<int>, std::random_access_iterator_tag>::_Self 
    __gnu_debug::operator+(const _Self&, 
    __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, 
    std::__cxx1998::vector<int, std::allocator<int> > >, 
    std::__debug::vector<int>, 
    std::random_access_iterator_tag>::difference_type)

Error: attempt to advance a dereferenceable (start-of-sequence) iterator 10 
steps, which falls outside its valid range.

Objects involved in the operation:
    iterator @ 0x0x7fffffffb900 {
      type = __gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > > (mutable iterator);
      state = dereferenceable (start-of-sequence);
      references sequence with type 'std::__debug::vector<int, std::allocator<int> >' @ 0x0x7fffffffb8c0
    }

  • N4659(2017 年 3 月 Kona 后工作草案/C++17 DIS)

好吧,根據標准§5/5.7定義超出范圍的迭代器是 UB:

當具有整數類型的表達式被添加到指針或從指針中減去時,結果具有指針操作數的類型。 如果指針操作數指向數組 object 的元素,並且數組足夠大,則結果指向與原始元素偏移的元素,使得結果和原始數組元素的下標之差等於整數表達式。 換句話說,如果表達式指向數組 object i-th元素,則表達式(P)+N (等價於N+(P))(P)-N (其中N具有值 n)指向,分別是數組對象的i+n-th和第i−n-th元素,前提是它們存在。 此外,如果表達式P指向數組 object 的最后一個元素,則表達式(P)+1指向數組 object 的最后一個元素,如果表達式 Qpointsone 超過數組 ZA8CFDE6331BD49EB2AC96F8911 的最后一個元素(Q)-1指向數組對象的最后一個元素。 如果指針操作數和結果都指向同一個數組 object 的元素,或數組 object 的最后一個元素,則評估不應產生溢出; 否則,行為未定義

如果您打開 gcc 的迭代器調試,您可以驗證這一點

# g++ main.cpp -D_GLIBCXX_DEBUG -o main
# ./main
C:/mingw-w64/i686-8.1.0-win32-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/debug/safe_iterator.h:374:
Error: attempt to advance a dereferenceable (start-of-sequence) iterator 10
steps, which falls outside its valid range.

Objects involved in the operation:
    iterator @ 0x0061FE3C {
      type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > >, std::__debug::vector<int, std::allocator<int> > > (mutable iterator);
      state = dereferenceable (start-of-sequence);
      references sequence with type 'std::__debug::vector<int, std::allocator<int> >' @ 0x0061FE50
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM