Reputation: 2748
To get to the point: is the following safe ?
vector<int> v;
int const* last = &*v.end();
// last is never dereferenced
My concern is that the trick to get a plain old pointer from an iterator forces to dereference the end() iterator, which is not valid... even if it is just to take the pointer back!
Backgroud: I am trying to create a collection of entries indexed by arbitrary types (especially integers and pointer to objects).
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;
}
Upvotes: 5
Views: 1429
Reputation: 310950
The iterator returned by member function end()
"points" after the last element of a vector. You may not dereference it. Otherwise the program will have undefined behavior.
You can get the corresponding pointer the following way
vector<int> v;
int const *last = v.data() + v.size();
If you want to use the iterator returned by the member function end() you can write
vector<int> v;
int const *last = v.data() + std::distance( v.begin(), v.end() );
Take into account that member function data() returns a raw pointer of the memory extent occupied by vector's data.
Upvotes: 1
Reputation: 36597
Dereferencing an end()
iterator gives undefined behaviour, with any standard container.
For a vector you can get a pointer corresponding to the end()
iterator using
pointer_to_end = v.empty() ? 0 : (&(*v.begin()) + v.size());
or
pointer_to_end = v.data() + v.size(); // v.data() gives null is size is zero
The check of v.empty()
is needed since, if v
is empty, v.begin() == v.end()
. For C++11 or later, use of nullptr
instead of 0
in the above is often considered preferable.
Upvotes: 3