将end()迭代器转换为指针

5
直接说:以下内容是否安全?
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;
}

1
就我所知,“由任意类型索引的条目集合”听起来很像映射的定义... - Oliver Charlesworth
3
使用v.data() + v.size()会更安全。 - Alan Stokes
2
知道end()指的是最后一个元素之后的元素,对吧? - Jesper Juhl
@OliverCharlesworth 是的,但在我的实际情况中,使用地图无法帮助处理数据的方式。 - Bérenger
@ JesperJuhl 是的,理想情况下,我希望 vector<T>::const_iterator == T const* 。 - Bérenger
2个回答

3

对于任何标准容器,在解引用end()迭代器时会导致未定义的行为。

对于 vector ,可以使用以下方式获取与 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 通常被认为更可取。


2
如果 v 是空的,那么 v.begin() == v.end()。那么为什么你会想要在这里得到 0 作为结果呢? - Oliver Charlesworth
3
如果 v.begin() == v.end(),那么对 v.begin() 解引用会产生未定义的行为。 - Peter
好的,这很有道理。不过,这也需要对OP的代码进行更一般性的修改。 - Oliver Charlesworth
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Bérenger
这是你的集合设计问题。我只是按照你提出的问题进行回答。 - Peter
显示剩余4条评论

1
成员函数 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()返回一个原始指针,该指针指向vector数据所占用的内存空间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接