简体   繁体   中英

C++11 auto iterator type with std::begin(), std::end() issue

I have some private class member, representing random access array of std::deque containing some data:

std::vector<std::deque<SomeDataClass> > someMember;

I would like to provide a public class method which returns iterable data structure, containing all data elements from my array of deques:

std::deque<SomeDataClass> someMethod();

I would like this method go through all the deques in vector and copy every element on it's way to local std::deque, eventually returning this local std::deque by value. I'm trying to implement this method using C++11 auto and std::begin() , std::end() :

std::deque<SomeDataClass> MyClassName::someMethod(){
    std::deque<DirectedEdge> allDataItems;
    std::deque<DirectedEdge>::iterator deqIter = allDataItems.begin();
    for(auto it = std::begin(someMember); it != std::end(someMember); ++it){
        std::copy(std::begin(*it), std::end(*it), deqIter);
    }

    return allDataItems;
}

I receive data access violation unhandled exception error on runtime in deque header. What is a mistake?

std::copy() requires the destination range to be large enough to hold the copy, but allDataItems is empty. You'd have to reserve space in allDataItems in advance (but that's not possible with std::deque ). You should use a std::back_inserter (defined in <iterator> ) instead:

std::deque<SomeDataClass> MyClassName::someMethod(){
    std::deque<DirectedEdge> allDataItems;
    for(auto it = std::begin(someMember); it < std::end(someMember); ++it){
        std::copy(std::begin(*it), std::end(*it), std::back_inserter(allDataItems));
    }

    return allDataItems;
}

Here is an idomatic C+11 way to do it:

std::deque<SomeDataClass> MyClassName::someMethod() {
  std::deque<DirectedEdge> allDataItems;

  for( auto const& dq : someMember ) {
    allDataItems.insert( allDataItems.end(), std::begin(dq), std::end(dq) );
  }
  return allDataItems;
}

another way would be to write a concatinate function:

struct concatenate {
  template<typename Dest, typename Src>
  Dest&& operator()( Dest&& d, Src const& s ) const {
    using std::begin; using std::end;
    typename std::decay<Dest>::type retval = std::forward<Dest>(d);
    retval.insert( end(retval), begin(s), end(s) );
    return std::move(retval);
  }
};
std::deque<SomeDataClass> MyClassName::someMethod() {
  using std::begin; using std::end; // enable ADL
  return std::accumulate(
    begin(someMember), end(someMember),
    std::deque<DirectedEdge>(), concatenate()
  );
}

which is pretty cute. If you don't like std::accumulate ,

std::deque<SomeDataClass> MyClassName::someMethod() {
  std::deque<DirectedEdge> allDataItems;

  for( auto const& dq : someMember ) {
    allDataItems = concatenate( std::move(allDataItems), dq );
  }
  return allDataItems;
}

both of which are roughly equivalently efficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM