TransWikia.com

Valid way of accessing the address of the one-past-end element of a vector

Stack Overflow Asked by Jean-Joël Borter on January 15, 2021

I wanted to implement an iterator to use a custom class in a for range loop. The iterator access an internal std::vector of std::unique_ptr of a Base class and returns a raw pointer to a child class.

This is what I came up with:

using upBase = std::unique_ptr<Base>;

class Test
{
   std::vector<upBase> list;
public:
   void Add(upBase&& i) { list.push_back(std::move(i)); }

   class iterator
   {
      upBase* ptr;
   public:
      iterator(upBase* p) : ptr(p)   {}
      bool         operator!=(const iterator& o) { return ptr != o.ptr; }
      iterator&    operator++()      { ++ptr; return *this; }
      Child&       operator*()       { return *(Child*)(*ptr).get(); }
      const Child& operator*() const { return *(Child*)(*ptr).get(); }

   };
   iterator begin() { return iterator(&list[0]); }
   iterator end()   { return iterator(&list[list.size()]); }
};

This works fine on the latest compilers (tested on GodBolt with GCC, Clang and MSVC) but when using Visual Studio 2015 the end() method throws a run-time exception:

 Debug assertion failed. C++ vector subscript out of range.

I search the internet for a proper way to access the address of the one-past-end element of a std::vector, but didn’t find anything except complicated pointer arithmetic.

I finally came up with the following implementation for the begin() and end() methods:

iterator begin() { return iterator(&list.front()); }
iterator end()   { return iterator(&list.back() + 1); }

This doesn’t complain at run-time. Is it the correct way to access the address of the one-past-end element of an std::array or std::vector?

If not, what would be the proper way?

One Answer

What would be the proper way?

You are trying to re-invent the wheel. You do not need to implement the class iterator for your Test, as you could get the begin and end iterator from the list (i.e. std::vector<upBase>::begin and std::vector<upBase>::end)

Therefore just make them available via corresponding member functions in Test class:

class Test
{
    std::vector<upBase> list;
public:
    void Add(upBase&& i) { list.push_back(std::move(i)); }

    auto begin() /* const noexcept */ { return list.begin();  }
    auto end() /* const noexcept */ { return list.end(); }
};

(See a demo here)


Also note that the auto return is only possible since . If the compiler does not support C++14, you can provide it as trailing return type, as follows (assuming at least you have access to ):

auto begin() -> decltype(list.begin()) { return list.begin();  }
auto end() ->  decltype(list.end())    { return list.end(); }

Correct answer by JeJo on January 15, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP