【问题标题】:Convert the end() iterator to a pointer将 end() 迭代器转换为指针
【发布时间】:2016-07-17 12:51:38
【问题描述】:

切入正题:以下安全吗?

vector<int> v;
int const* last = &*v.end(); 
// last is never dereferenced

我担心的是,从迭代器中获取普通旧指针的技巧会强制取消对 end() 迭代器的引用,这是无效的……即使只是为了取回指针!

背景:我正在尝试创建一个由任意类型(尤其是整数和指向对象的指针)索引的条目集合。

template<class IT>
/// requires IT implements addition (e.g. int, random-access iterator)
class IndexingFamily {
    public:
        using IndexType = IT;

        IndexingFamily(IndexType first, IndexType last);
        int size() const;
        IndexType operator[](int i) const;
    private:
        IndexType first;
        IndexType last;
};

template<class IT> IndexingFamily<IT>::
IndexingFamily(IndexType first, IndexType last) 
    : first(first)
    , last(last) {}

template<class IT> auto IndexingFamily<IT>::
size() const -> int {
    return last-first;
}

template<class IT> auto IndexingFamily<IT>::
operator[](int i) const -> IndexType {
    return first+i;
}

template<class IT, class ET>
struct IndexedEntry {
    using IndexType = IT;
    using EntryType = ET;

    IndexType index;
    EntryType entry;
};

template<class IT, class ET>
class CollectionOfEntries {
    public:
        using IndexType = IT;
        using EntryType = ET;

        /// useful methods
    private:
        IndexingFamilyType indexingFamily;
        vector<EntryType> entries;
};


struct MyArbitraryType {};


int main() {
    MyArbitraryType obj0, obj1, obj2;
    vector<MyArbitraryType> v = {obj0,obj1,obj2};

    using IndexType = MyArbitraryType const*;
    IndexingFamily<IndexType> indexingFamily(&*v.begin(),&*v.end());

    using EntryType = double;
    using IndexedEntryType = IndexedEntry<IndexType,EntryType>;
    IndexedEntry entry0 = {&obj0,42.};
    IndexedEntry entry1 = {&obj1,43.};
    vector<IndexedEntryType> entries = {entry0,entry1};

    CollectionOfEntries coll = {indexingFamily,entries};

    return 0;
}

【问题讨论】:

  • FWIW,“由任意类型索引的条目集合”听起来很像地图的定义...
  • v.data() + v.size() 会更安全。
  • 知道 end() 指的是最后一个元素,对吧?
  • @OliverCharlesworth 是的,但在我的真实案例中,地图对处理数据的方式没有帮助
  • @JesperJuhl 是的,理想情况下,我想要 vector::const_iterator == T const*

标签: c++ pointers iterator


【解决方案1】:

取消引用 end() 迭代器会产生未定义的行为,适用于任何标准容器。

对于向量,您可以使用与end() 迭代器对应的指针

pointer_to_end = v.empty() ? 0 : (&(*v.begin()) + v.size());

pointer_to_end = v.data() + v.size();   // v.data() gives null is size is zero

需要检查v.empty(),因为如果v 为空,则v.begin() == v.end()。对于 C++11 或更高版本,使用nullptr 而不是上面的0 通常被认为是更可取的。

【讨论】:

  • "如果 v 为空,v.begin() == v.end()" - 为什么你会想要 0 作为这里的结果?
  • 我明白这一点,但仍然不清楚你为什么想要它而不是 v.begin() 作为结果。
  • (&amp;(*v.begin()) + v.size())(相当于&amp;*v.begin())?
  • 如果 v.begin() == v.end() 然后取消引用 v.begin() 具有未定义的行为。
  • 你的答案是好的,除了那个空的情况:指针越过最后一个元素的末尾,选择以统一的方式处理空范围,所以它有点失败......
【解决方案2】:

成员函数end()返回的迭代器“指向”向量的最后一个元素。您可能不会取消引用它。否则程序将有未定义的行为。

可以通过以下方式获取对应的指针

vector<int> v;
int const *last = v.data() + v.size(); 

如果你想使用成员函数end()返回的迭代器你可以写

vector<int> v;
int const *last = v.data() + std::distance( v.begin(), v.end() ); 

考虑到成员函数 data() 返回向量数据占用的内存范围的原始指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 2023-04-04
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 2015-04-28
    • 1970-01-01
    相关资源
    最近更新 更多