c++ - C++11 cast const iterator pointing to container of shared_ptr objects -


i have stl container element type const std::shared_ptr<myclass>.

i want supply 2 iterator types user:

  1. mycontainer::iterator

typedefed std::vector<const std::shared_ptr<myclass>>::iterator (which should same type std::vector<const std::shared_ptr<const myclass>>::const_iterator

  1. mycontainer::const_iterator

typedefed std::vector<const std::shared_ptr<const myclass>>::iterator (which should same type std::vector<const std::shared_ptr<const myclass>>::const_iterator

in other words, want "const" refer myclass constness, not shared_ptr constness. solution found getting second iterator type getting first one, easy (e.g. using vector::begin), , converting second type using static_cast (fixme: no need use const_cast because i'm adding constness, not removing it).

would common good-design way achieve that, or there's better/more common way?

typedefed std::vector<const std::shared_ptr<myclass>>::iterator (which should same type std::vector<std::shared_ptr<const myclass>>::const_iterator

but isn't same type. iterators not pointers. if iterator , const_iterator types defined inside vector unrelated types:

template<typename t> class vector {     class iterator;     class const_iterator;     // ... 

vector<const int> different type vector<int> , nested types different. far compiler concerned unrelated types, i.e. cannot move const around point in type , compatible types:

vector<const shared_ptr<const t>>::iterator 

you cannot use const_cast convert between unrelated types. can use static_cast convert vector<t>::iterator vector<t>::const_iterator it's not cast, you're constructing latter former, allowed because conversion required standard.

you can convert shared_ptr<const t> shared_ptr<t> const_pointer_cast<t> again because it's defined work standard, not because types inherently compatible , not because "just works" plain ol' pointers.

since vector's iterators don't provide deep-constness want, you'll need write own, it's not hard:

class myclass { };  class mycontainer {     typedef std::vector<std::shared_ptr<myclass>> container_type;      container_type m_cont;  public:      typedef container_type::iterator iterator;      class const_iterator     {         typedef container_type::const_iterator internal_iterator;         typedef std::iterator_traits<internal_iterator> internal_traits;          const_iterator(internal_iterator i) : m_internal(i) { }         friend class mycontainer;      public:          const_iterator() { }         const_iterator(iterator i) : m_internal(i) { }          typedef std::shared_ptr<const myclass> value_type;         typedef const value_type& reference;         typedef const value_type* pointer;         typedef internal_traits::difference_type difference_type;         typedef internal_traits::iterator_category iterator_category;          const_iterator& operator++() { ++m_internal; return *this; }         const_iterator operator++(int) { const_iterator tmp = *this; ++m_internal; return tmp; }          reference operator*() const { m_value = *m_internal; return m_value; }         pointer operator->() const { m_value = *m_internal; return &m_value; }          // ...      private:         internal_iterator m_internal;         mutable value_type m_value;     };      iterator begin() { return m_cont.begin(); }     const_iterator begin() const { return const_iterator(m_cont.begin()); }      // ...     }; 

that iterator type mising few things (operator--, operator+) they're easy add, following same ideas shown.

the key point notice in order const_iterator::operator* return reference, there needs shared_ptr<const myclass> object stored member of iterator. member acts "cache" shared_ptr<const myclass> value, because underlying container's real elements different type, shared_ptr<myclass>, need somewhere cache converted value reference can returned. n.b. doing breaks iterator requirements, because following doesn't work expected:

mycontainer::const_iterator ci = c.begin(); const shared_ptr<const myclass>& ref = *ci; const myclass* ptr = ref.get(); ++ci; (void) *ci; assert( ptr == ref.get() );  // fail! 

the reason assertion fails *ci doesn't return reference underlying element of container, member of iterator, gets modified following increment , dereference. if behaviour isn't acceptable you'll need return proxy iterator instead of caching value. or return shared_ptr<const myclass> when const_iterator dereferenced. (the difficulties of getting 100% right 1 of reasons stl containers don't try model deep constness!)

a lot of effort of defining own iterator types done boost::iterator_adaptor utility, example above useful exposition. adaptor you'd need own custom iterator types desired behaviour:

struct iterator : boost::iterator_adaptor<iterator, container_type::iterator> {     iterator() { }     iterator(container_type::iterator i) : iterator_adaptor(i) { } };  struct const_iterator : boost::iterator_adaptor<const_iterator, container_type::const_iterator, std::shared_ptr<const myclass>, boost::use_default, std::shared_ptr<const myclass>> {     const_iterator() { }     const_iterator(iterator i) : iterator_adaptor(i.base()) { }     const_iterator(container_type::const_iterator i) : iterator_adaptor(i) { } }; 

Comments

Popular posts from this blog

how to insert data php javascript mysql with multiple array session 2 -

multithreading - Exception in Application constructor -

windows - CertCreateCertificateContext returns CRYPT_E_ASN1_BADTAG / 8009310b -