2008-12-09 4 views
14

Je me demandais s'il y a un itérateur dans la STL qui déréférence l'objet pointé avant de le renvoyer. Cela pourrait être très utile lors de la manipulation de conteneurs agrégeant des pointeurs. Voici un exemple de ce que je voudrais être en mesure de le faire:Y a-t-il un dereference_iterator dans la STL?

#include <vector> 
#include <iterator> 
#include <algorithm> 

using namespace std; 

int main() 
{ 
    vector<int*> vec; 

    int i = 1; 
    int j = 2; 
    int k = 3; 

    vec.push_back(&i); 
    vec.push_back(&j); 
    vec.push_back(&k); 

    copy(deref_iterator(vec.begin()), 
     deref_iterator(vec.end()), 
     ostream_iterator<int>(cout, " ")); // prints "1 2 3" 

    return 0; 
} 

Répondre

11

Essayez Boost de indirect_iterator. Un indirect_iterator a la même catégorie que l'itérateur qu'il enveloppe. Par exemple, un indirect_iterator<int**> est un itérateur à accès aléatoire.

+0

Exactement ce que je demandais. Honte à moi de ne pas penser à Boost :-)! Cependant, je me serais attendu à ce qu'un tel itérateur soit présent dans la bibliothèque standard ... –

+0

Eh bien, le problème le plus difficile peut-il être résolu? Je veux trier le vecteur de ptrs ou le partitionner en appliquant des fonctions de . Le problème ici est que j'ai besoin d'échanger des pointeurs dans le conteneur alors que je déréférencer les valeurs de l'objet. – 0x2207

4

S'il est impossible à l'aide Boost, l'écriture d'un itérateur personnalisé est pas difficile. Voici un exemple d'un « déréférencement iterator » qui répond aux exigences de InputIterator:

#include <iterator> 

template <typename T> 
struct PointedType; 

template <typename T> 
struct PointedType<T*> 
{ 
    typedef T value_type; 
}; 

template <typename InputIterator> 
struct DerefIterator 
{ 
    typedef input_iterator_tag iterator_category; 
    typedef typename PointedType< 
      typename iterator_traits<InputIterator>::value_type>::value_type 
      value_type; 
    typedef typename iterator_traits<InputIterator>::difference_type 
      difference_type; 
    typedef value_type* pointer; 
    typedef value_type& reference; 

    public: 
    explicit DerefIterator(const InputIterator& ii) 
     : it(ii) {} 

    // Returns the object pointed by the object referenced by it 
    reference operator*() const { return **it; } 
    pointer operator->() const { return *it; } 

    DerefIterator& operator++() 
    { 
     ++it; 
     return *this; 
    } 

    DerefIterator operator++(int) 
    { 
     DerefIterator tmp = *this; 
     ++it; 
     return tmp; 
    } 

    bool equals(const DerefIterator<InputIterator> & di) const 
    { 
     return di.it == it; 
    } 

    private: 
    InputIterator it; 
}; 

// Equality functions 

template <typename InputIterator> 
inline bool operator==(const DerefIterator<InputIterator>& di1, 
         const DerefIterator<InputIterator>& di2) 
{ 
    return di1.equals(di2); 
} 

template <typename InputIterator> 
inline bool operator!=(const DerefIterator<InputIterator>& di1, 
         const DerefIterator<InputIterator>& di2) 
{ 
    return ! (di1 == di2); 
} 

//Helper function 

template <typename InputIterator> 
DerefIterator<InputIterator> deref_iterator(const InputIterator& ii) 
{ 
    return DerefIterator<InputIterator>(ii); 
} 
+0

Vous devez utiliser 'using namespace std;' pour ce qui précède de compiler. –

+0

@DavidDoria: Une meilleure approche consiste à préfixer 'input_iterator_tag' et' iterator_traits' avec le préfixe 'std'. –

4

En supposant que votre cas d'utilisation réel est un peu plus complexe qu'un conteneur de pointeurs entiers!

Vous pouvez vérifier les conteneurs ptr boost
http://www.boost.org/doc/libs/1_35_0/libs/ptr_container/doc/reference.html

Les conteneurs contiennent des objets alloués dynamiquement (par exemple pointeurs).
Mais tout accès aux objets (direct ou via itérateur) renvoie une référence à l'objet.

#include <boost/ptr_container/ptr_vector.hpp> 
#include <iostream> 
#include <iterator> 
#include <algorithm> 

using namespace std; 

int main() 
{ 
    boost::ptr_vector<int> vec; 

    vec.push_back(new int(1)); 
    vec.push_back(new int(2)); 
    vec.push_back(new int(3)); 

    copy(vec.begin(),vec.end(), 
     ostream_iterator<int>(std::cout, " ")); // prints "1 2 3 " 

    return 0; 
} 
+0

Eh bien, c'est bien si vous voulez que le conteneur ait la propriété des éléments. L'attribut indirect_iterator semble plus approprié lorsqu'il s'agit de pointeurs sur un objet avec une sémantique d'entité qui sont déjà détenus par quelque chose d'autre (ou alloués sur la pile). –