Boost logo

Boost Users :

Subject: [Boost-users] [Multi-Index] crash on iterator copy or assignment
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2009-03-12 14:50:03


Hi,

I've been using B.MI for a few days, and until now it's worked great
for me. I've included below in Exhibit A a simplified (and a bit
obfuscated, sorry) version of what I've been using (a proxy, indexed
by name and type, and a method returning all instances of a given
type).

Filling in a list of all entries matching a given type (in exhibit A)
works great.

But now I was trying to return a custom (non-standard) iterator, where
the client gets a pointer to a abstract base iterator (allows to hide
the B.MI stuff in the concrete derived iterator), wrapped in an
auto_ptr. The private concrete iterator internally stores the B.MI
iterator from the index I'm interested in (exhibit B). This compiles
(vs2005 sp1 on winXP 32), but it crashes at runtime on the call to
boost::tie, during iterator assignment apparently. (call stack in
exhibit C).

So at this point I have no clue what's going on, and I would
appreciate some help. The level of template complexity is more
than stretching my abilities I'm afraid, just reading the type names
makes my end spin ;) We're going to try it using GCC on Linux
to see if it might be a compiler issue, and possibly try vs2008 as
well, but if anyone knows if taking copies of the iterators is allowed
(I know the index themselves shouldn't be copied, and we don't), and
if yes why it's failing in this particular case, I'd appreciate.

Thanks, --DD

PS: Earlier I had a version of ByTypeFooIterator that took the
begin/end iterator as param to its Ctor, taking a *copy*, but that
also crashed w/o a stack trace this time.

PPS: What I was trying to test in fact was whether I could get two
  equal ranges for two different MyTypeInfo, and iterate on those but
  interleaving the calls to ++iter, to verify nested or interleaved iteration
  was valid with B.MI. But I never reached that point.

=== Exhibit A: the code that works ===

struct FooProxy {
   Foo*const foo_;
   FooProxy(Foo* foo) : foo_(foo) {}
   const MyString& get_name() const { return foo_->name(); }
   const MyTypeInfo& get_type() const { return foo_->type_info(); }
};

struct ByName {};
struct ByType {};

typedef boost::multi_index_container<
   FooProxy ,
   indexed_by<
       hashed_non_unique<
           tag<ByName>,
           BOOST_MULTI_INDEX_CONST_MEM_FUN(
               FooProxy , const MyString&, get_name
           )
>,
       hashed_non_unique<
           tag<ByType>,
           BOOST_MULTI_INDEX_CONST_MEM_FUN(
               FooProxy , const MyTypeInfo&, get_type
           )
>
>
> FooIndex;

FooIndex foo_index_;

typedef FooIndex::index<ByName>::type FoosByName;
typedef FooIndex::index<ByType>::type FoosByType;

size_t select_foos(const MyTypeInfo& tinfo, MyList<Foo*>& list) {
   size_t count = 0;
   FoosByType::iterator range_begin, range_end;
   FoosByType& by_type = get<ByType>(foo_index_);
   boost::tie(range_begin, range_end) = by_type.equal_range(tinfo);
   for (FoosByType::iterator i = range_begin; i != range_end; ++i) {
       const FooProxy& proxy = *i;
       list.append(proxy.foo_);
       ++count;
   }
   return count;
}

=== Exhibit B: the code that crashes ===

// public abstract base iterator
class FooIterator {
public:
   virtual ~FooIterator() {}

   virtual bool more() const = 0;
   virtual Foo* cur() const = 0;
   virtual void next() = 0;

protected:
   FooIterator() {}
};

// private concrete iterator
struct ByTypeFooIterator : public FooIterator {
   FoosByType::iterator cur_, end_;

   virtual bool more() const {
       return cur_ != end_;
   }
   virtual Foo* cur() const {
       return cur_->foo_;
   }
   virtual void next() {
       ++cur_;
   }
};

// public method
std::auto_ptr<FooIterator> iterate(const MyTypeInfo& tinfo) {
   FoosByType& by_type = get<ByType>(foo_index_);
   std::auto_ptr<ByTypeFooIterator > iter_ptr = new ByTypeFooIterator;
   boost::tie(iter_ptr->cur_, iter_ptr->end_) = by_type.equal_range(tinfo);
   return iter_ptr;
}

// part of unit test
   Foo*const expected_bar = ...; // Bar derives from Foo
   for (std::auto_ptr<FooIterator> i = iterate(Bar::tinfo());
i->more(); i->next()) {
       Foo*const curr = i->cur();
       CPPUNIT_ASSERT_EQUAL(expected_bar, curr); // only one Bar here
   }

=== Exhibit C: call stack of crash ===

(actual FooIndex contains more indices than shown in exhibit A above).

> my_lib.dll!std::_Iterator_base::operator=(const std::_Iterator_base & _Right={...}) Line 374 + 0x8 bytes C++

       my_lib.dll!std::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &>::operator=(const
std::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy const
*,FooProxy const &> & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::detail::iterator_base<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &>::operator=(const
boost::detail::iterator_base<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &>::operator=(const
boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy const
*,FooProxy const &> & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> >::operator=(const
boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::incrementable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > >::operator=(const
boost::incrementable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > > & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::equality_comparable1<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::incrementable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > > >::operator=(const
boost::equality_comparable1<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::incrementable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::dereferenceable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<&
__that={...}) + 0x18 bytes C++

       my_lib.dll!boost::input_iteratable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> >::operator=(const
boost::input_iteratable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::forward_iteratable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> >::operator=(const
boost::forward_iteratable<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy const
*,boost::iterator<std::forward_iterator_tag,FooProxy,int,FooProxy
const *,FooProxy const &> > & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::forward_iterator_helper<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy,int,FooProxy const *,FooProxy const &>::operator=(const
boost::forward_iterator_helper<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,FooProxy,int,FooProxy const *,FooProxy const &> & __that={...}) +
0x18 bytes C++

       my_lib.dll!boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >::operator=(const
boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> > & __that={...}) + 0x18 bytes C++

       my_lib.dll!boost::tuples::tuple<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> > &,boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> > &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::operator=<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> > >(const std::pair<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> >,boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<FooProxy,std::allocator<FooProxy>
> > >,boost::multi_index::detail::bucket_array<std::allocator<FooProxy>
> > > & k=({node=0x04680080 buckets=0x04667bac },{node=0x04667c68
buckets=0x04667bac })) Line 638 C++

       my_lib.dll!iterate(const MyTypeInfo & tinfo={...}) Line 510 +
0x51 bytes C++


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net