OK The problem is how stl moves memory. He used swap () all the time, then everything will be fine, but sometimes it happens (from gnu stl_algo.h __insertion_sort)
if (__comp(*__i, *__first)) { // COPY VALUE INTO TEMPORARY MEMORY typename iterator_traits<_RandomAccessIterator>::value_type __val = _GLIBCXX_MOVE(*__i); // MOVE MEMORY AROUND _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1); // COPY TEMPORARY VALUE BACK *__first = _GLIBCXX_MOVE(__val); }
So, we see that the :: value_type iterator should store the value. It cannot, by itself, be a pointer. If it was a pointer, then it completes the cancellation of the pseudo-context approach shown above.
Therefore, we need to create a helper class, which is a set of VALUES values, not a set of ITERATORS. We can return this helper class when the pit dereferencing operator is constant, for example,
value_type operator*() const { return helper_class_value_collection_ctor( _args_ ); };
Thus, we can store values ββin new memory.
In addition, we need to create another helper class, which is a set of ITERATORS, unlike VALUES, so expressions like
*piterator_a = *piterator_b
. If * piterator_a is returned by value, then setting these values ββis pointless because the return value is temporary. Thus, in this case, we need a dereference operator to return a reference type (a collection of iterators), which will be stored as a private member variable of the piterator.
reference operator*() { return private_reftype_variable; };
So, this completely leads to the following.
#include <vector> #include <iostream> #include <utility> #include <iterator> #include <algorithm> // forward decl template <typename T,typename U> struct piterator_iterators; template <typename T,typename U> struct piterator_values { // This class holds memory; it is a value_type // It only serves the purpose of // allowing the stl to hold temporary values when moving memory around. // If the stl called sort(), then this class wouldn't be necessary. // // Note that the memory may be set by a piterator_iterators class, // which is a pseudo-value_type that points at memory, instead of holding memory. // // YOU NEED THIS SO THAT // typename piterator<T,U>::value_type Tmp = *piterator_a // PLACES THE VALUES INTO SOME (ACTUAL) TEMPORARY MEMORY, AS OPPOSED // TO CREATING A NEW POINTER TO EXISTING MEMORY. typedef typename T::value_type first_value; typedef typename U::value_type second_value; first_value first; second_value second; piterator_values() {}; piterator_values( first_value const & first , second_value const & second ) : first(first), second(second) {}; piterator_values( piterator_values<T,U> const & rhs ) : first(rhs.first), second(rhs.second) { }; piterator_values( piterator_iterators<T,U> const & rhs ) : first(*rhs.first), second(*rhs.second) { }; piterator_values<T,U> & operator=( piterator_values<T,U> const & rhs ) { if( &rhs != this ) { first = rhs.first; second = rhs.second; } return *this; }; piterator_values<T,U> & operator=( piterator_iterators<T,U> const & rhs ) { if( &rhs != this ) { first = *rhs.first; second = *rhs.second; } return *this; }; friend void swap( piterator_values<T,U> & lhs, piterator_values<T,U> & rhs ) { using std::swap; swap(lhs.first,rhs.first); swap(lhs.second,rhs.second); }; }; template <typename T,typename U> struct piterator_iterators { T first; U second; // This class does not hold memory; it points at existing memory. // It is a pseudo-value_type. When the piterator dereferences, it // will return a piterator_iterators object IF it is a nonconst reference. // This class is used as a "reference" for an actual iterator, // so assignment operators change the value of the thing pointed at, // as opposed to reseting the address of what is being pointed at. // // YOU NEED THIS SO THAT // *piterator_a = *piterator_b // MAKES SENSE. // IF THE DEREFERENCE PASSED A piterator_values, // THEN IT WOULD ONLY MODIFY A TEMPORARY, NOT THE ACTUAL THING // piterator_iterators() {}; piterator_iterators( T const & first , U const & second ) : first(first), second(second) {}; piterator_iterators( piterator_iterators<T,U> const & rhs ) : first(rhs.first), second(rhs.second) {}; piterator_iterators<T,U> & operator=( piterator_iterators<T,U> const & rhs ) { if( &rhs != this ) { *first = *rhs.first; *second = *rhs.second; } return *this; }; piterator_iterators<T,U> & operator=( piterator_values<T,U> const & rhs ) { *first = rhs.first; *second = rhs.second; return *this; }; friend void swap( piterator_iterators<T,U> & lhs, piterator_iterators<T,U> & rhs ) { using std::swap; std::iter_swap(lhs.first,rhs.first); std::iter_swap(lhs.second,rhs.second); }; }; // // iterator of pair of iterators // template <typename T, typename U> class piterator : public std::iterator< std::random_access_iterator_tag, piterator_values<T,U>, std::ptrdiff_t, piterator_iterators<T,U> *, piterator_iterators<T,U> & > { typedef piterator<T,U> iter; public: typedef std::random_access_iterator_tag iterator_catagory; typedef typename piterator<T,U>::value_type value_type; typedef typename piterator<T,U>::difference_type difference_type; typedef typename piterator<T,U>::pointer pointer; typedef typename piterator<T,U>::reference reference; typedef piterator_iterators<T,U> value_of_reference; //typedef typename piterator_iterators<T,U> & reference; public: piterator() {}; piterator( iter const & rhs ) { mp.first = rhs.mp.first; mp.second = rhs.mp.second; }; piterator( value_of_reference const rhs ) { mp.first = rhs.first; mp.second = rhs.second; }; piterator( T const first, U const second ) { mp.first = first; mp.second = second; }; iter & operator=( iter const & rhs ) { if ( &rhs != this ) { mp.first = rhs.mp.first; mp.second = rhs.mp.second; }; return *this; } friend void swap( iter & lhs , iter & rhs ) { using std::swap; swap(lhs.mp,rhs.mp); } public: // Comparison bool operator< ( iter const & rhs ) const { return mp.first < rhs.mp.first; } bool operator> ( iter const & rhs ) const { return mp.first > rhs.mp.first; } bool operator==( iter const & rhs ) const { return mp.first == rhs.mp.first; } bool operator!=( iter const & rhs ) const { return mp.first != rhs.mp.first; } public: // Iteration iter & operator++() { ++(mp.first); ++(mp.second); return *this; } iter & operator--() { --(mp.first); --(mp.second); return *this; } iter operator++(int) { iter tmp(*this); ++(*this); return tmp; } iter operator--(int) { iter tmp(*this); --(*this); return tmp; } public: // Step iter & operator+=( difference_type n ) { mp.first += n; mp.second += n; return *this; } iter & operator-=( difference_type n ) { mp.first -= n; mp.second -= n; return *this; } iter operator+ ( difference_type n ) { iter result(*this); return result += n; } iter operator- ( difference_type n ) { iter result(*this); return result -= n; } difference_type operator+ ( iter const & rhs ) { return mp.first + rhs.mp.first; } difference_type operator- ( iter const & rhs ) { return mp.first - rhs.mp.first; } public: // Distance difference_type operator-( iter & rhs ) { return mp.first - rhs.mp.first; } public: // Access // reference if on the lhs of the eq. reference operator*() { return mp; } // value if on the rhs of the eq. value_type operator*() const { return value_type(*mp.first,*mp.second); } reference operator[]( difference_type n ) { return *( (*this) + n ); } pointer operator->() { return ∓ }; private: // State value_of_reference mp; };
Here's the main program, separated from above to see how it is used.
//////////////////////////////////////////////////////////////// template<class T,class U> bool proxy_comp( piterator_values<T,U> left, piterator_values<T,U> right ) { return left.first < right.first; } /////////////////////////////////////////////////////////////// int main() { std::vector<double> dv1(3); std::vector<double> dv2(3); std::vector<int> iv(3); dv1[0] = -0.5; dv1[1] = -1.5; dv1[2] = -2.5; dv2[0] = 10.5; dv2[1] = 11.5; dv2[2] = 12.5; iv[0] = 10; iv[1] = 20; iv[2] = 3; // // EXAMPLE 1: PAIR OF ITERATORS // typedef piterator< std::vector<int>::iterator , std::vector<double>::iterator > PAIR_ITER; PAIR_ITER pair_begin( iv.begin() , dv1.begin() ); PAIR_ITER pair_end( iv.end() , dv1.end() ); std::cout << "paired arrays now:" << std::endl; for ( PAIR_ITER p = pair_begin; p != pair_end; ++p ) std::cout << *p->first << " " << *p->second << std::endl; std::cout << "swap 1st and 3rd elements..." << std::endl; swap(*pair_begin,*(pair_begin+2)); std::cout << "paired arrays now:" << std::endl; for ( PAIR_ITER p = pair_begin; p != pair_end; ++p ) std::cout << *p->first << " " << *p->second << std::endl; std::cout << "calling sort..." << std::endl; std::sort( pair_begin , pair_end , &proxy_comp<std::vector<int>::iterator , std::vector<double>::iterator> ); std::cout << "paired arrays now:" << std::endl; for ( PAIR_ITER p = pair_begin; p != pair_end; ++p ) std::cout << *p->first << " " << *p->second << std::endl; // // EXAMPLE 2: TRIPLET (PAIR OF PAIR) // typedef piterator< std::vector<double>::iterator , std::vector<double>::iterator > DOUBLET_ITER; typedef piterator< std::vector<int>::iterator , DOUBLET_ITER > TRIPLET_ITER; TRIPLET_ITER triplet_begin( iv.begin(), DOUBLET_ITER( dv1.begin() , dv2.begin() ) ); TRIPLET_ITER triplet_end( iv.end(), DOUBLET_ITER( dv1.end() , dv2.end() ) ); std::cout << "tripleted arrays now:" << std::endl; for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p ) std::cout << *p->first << " " << *p->second->first << " " << *p->second->second << std::endl; std::cout << "iter_swap 1st and second elements..." << std::endl; std::iter_swap( triplet_begin , triplet_begin+1 ); std::cout << "tripleted arrays now:" << std::endl; for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p ) std::cout << *p->first << " " << *p->second->first << " " << *p->second->second << std::endl; std::cout << "calling sort..." << std::endl; std::sort( triplet_begin, triplet_end, &proxy_comp< std::vector<int>::iterator , piterator< std::vector<double>::iterator , std::vector<double>::iterator > > ); std::cout << "tripleted arrays now:" << std::endl; for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p ) std::cout << *p->first << " " << *p->second->first << " " << *p->second->second << std::endl; return 0; }
Here is the above program
paired arrays now: 10 -0.5 20 -1.5 3 -2.5 swap 1st and 3rd elements... paired arrays now: 3 -2.5 20 -1.5 10 -0.5 calling sort... paired arrays now: 3 -2.5 10 -0.5 20 -1.5 tripleted arrays now: 3 -2.5 10.5 10 -0.5 11.5 20 -1.5 12.5 iter_swap 1st and second elements... tripleted arrays now: 10 -0.5 11.5 3 -2.5 10.5 20 -1.5 12.5 calling sort... tripleted arrays now: 3 -2.5 10.5 10 -0.5 11.5 20 -1.5 12.5