Boost C++ Libraries: Ticket #11139: boost::container::vector<std::shared_ptr<const T>, std::allocator<T>>::const_iterator allows changing its dereferenced elements https://svn.boost.org/trac10/ticket/11139 <p> Consider the following attempt to make a <code>const_iterator</code> for a vector of smart pointers, be de-referentiable only to smart pointers to constant types: </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/container/vector.hpp&gt;</span><span class="cp"></span> <span class="k">class</span> <span class="nc">C</span> <span class="p">{</span> <span class="k">public</span><span class="o">:</span> <span class="k">using</span> <span class="n">a_type</span> <span class="o">=</span> <span class="kt">int</span><span class="p">;</span> <span class="k">using</span> <span class="n">shared_ptr</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">a_type</span><span class="o">&gt;</span><span class="p">;</span> <span class="k">using</span> <span class="n">shared_constptr</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">a_type</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// In my code, I am using a more complex allocator</span> <span class="c1">// in shared memory from boost::interprocess.</span> <span class="k">using</span> <span class="n">some_fixed_allocator</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="n">shared_ptr</span><span class="o">&gt;</span><span class="p">;</span> <span class="k">using</span> <span class="n">vector</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">container</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">shared_ptr</span><span class="p">,</span> <span class="n">some_fixed_allocator</span><span class="o">&gt;</span><span class="p">;</span> <span class="k">using</span> <span class="n">cvector</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">container</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">shared_constptr</span><span class="p">,</span> <span class="n">some_fixed_allocator</span><span class="o">&gt;</span><span class="p">;</span> <span class="n">C</span> <span class="p">()</span> <span class="p">{</span> <span class="n">shared_ptr</span> <span class="n">p</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">a_type</span><span class="o">&gt;</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">_v</span><span class="p">.</span><span class="n">push_back</span> <span class="p">(</span><span class="n">p</span><span class="p">);</span> <span class="p">}</span> <span class="n">cvector</span><span class="o">::</span><span class="n">const_iterator</span> <span class="n">first_element</span> <span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_v</span><span class="p">.</span><span class="n">begin</span> <span class="p">();</span> <span class="p">}</span> <span class="k">private</span><span class="o">:</span> <span class="n">vector</span> <span class="n">_v</span><span class="p">;</span> <span class="p">};</span> <span class="kt">int</span> <span class="nf">main</span> <span class="p">()</span> <span class="p">{</span> <span class="n">C</span> <span class="n">c</span><span class="p">;</span> <span class="n">C</span><span class="o">::</span><span class="n">cvector</span><span class="o">::</span><span class="n">const_iterator</span> <span class="n">it</span> <span class="o">=</span> <span class="n">c</span><span class="p">.</span><span class="n">first_element</span> <span class="p">();</span> <span class="o">**</span><span class="n">it</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// Expecting an error!</span> <span class="c1">// Note that we have an error using std::vector.</span> <span class="p">}</span> </pre></div></div><p> This compiled cleanly with G++ 4.9 with <code>-std=c++11</code>, which really is hiding the problem as the const_iterator allows changing elements of a the <code>cvector</code> type. </p> <p> Using a std::vector at least results in the following compilation error: </p> <pre class="wiki">allocator-rebind.cc: In member function ‘std::vector&lt;boost::shared_ptr&lt;const int&gt;, std::allocator&lt;int&gt; &gt;::const_iterator C::first_element() const’: allocator-rebind.cc:31:26: error: could not convert ‘((const C*)this)-&gt;C::_v.std::vector&lt;_Tp, _Alloc&gt;::begin&lt;boost::shared_ptr&lt;int&gt;, std::allocator&lt;int&gt; &gt;()’ from ‘std::vector&lt;boost::shared_ptr&lt;int&gt;, std::allocator&lt;int&gt; &gt;::const_iterator {aka __gnu_cxx::__normal_iterator&lt;const boost::shared_ptr&lt;int&gt;*, std::vector&lt;boost::shared_ptr&lt;int&gt;, std::allocator&lt;int&gt; &gt; &gt;}’ to ‘std::vector&lt;boost::shared_ptr&lt;const int&gt;, std::allocator&lt;int&gt; &gt;::const_iterator {aka __gnu_cxx::__normal_iterator&lt;const boost::shared_ptr&lt;const int&gt;*, std::vector&lt;boost::shared_ptr&lt;const int&gt;, std::allocator&lt;int&gt; &gt; &gt;}’ return _v.begin (); </pre><p> I suspect all the other containers in boost::container suffer from the same problem, e.g. they allow compilation of something wrong. </p> <p> Incidentally, it would be nice to have a way to rebind iterators for smart pointers, so that full encapsulation can be achieved also for <code>const</code> accessor methods. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11139 Trac 1.4.3 Eric Niebler Mon, 30 Mar 2015 22:46:14 GMT <link>https://svn.boost.org/trac10/ticket/11139#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11139#comment:1</guid> <description> <p> Says Ion Gaztañaga: </p> <blockquote class="citation"> <p> It's a bug. The following line in class vec_iterator (vector.hpp): </p> <p> typedef typename </p> <blockquote> <p> boost::intrusive::pointer_traits&lt;Pointer&gt; </p> <blockquote> <p> ptr_traits; </p> </blockquote> </blockquote> <p> should be pointer_traits&lt;pointer&gt; ("pointer" in lowercase). </p> </blockquote> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Tue, 31 Mar 2015 09:35:27 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/11139#comment:2 https://svn.boost.org/trac10/ticket/11139#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Thanks for the report. Fixed in: </p> <p> <a class="ext-link" href="https://github.com/boostorg/container/commit/ad54608d780f489d3e3119a097046da4fc23ce4e"><span class="icon">​</span>https://github.com/boostorg/container/commit/ad54608d780f489d3e3119a097046da4fc23ce4e</a> </p> <p> Hopefully in time for Boost 1.58 </p> Ticket