2010-09-12 5 views
0
template<typename OutputIterator> 
void BlitSurface::ExtractFrames(OutputIterator it, 
           int frame_width, int frame_height, 
           int frames_per_row, int frames_per_column, 
           bool padding) const 
{ 
    SDL_Surface ** temp_surf = SDL_Ex_ExtractFrames(_surface, frame_width, frame_height, frames_per_row, frames_per_column, padding); 

    int surface_count = frames_per_row * frames_per_column; 

    for(int i=0; i<surface_count; ++i) 
    { 
     BlitSurface bs; 
     bs._surface = temp_surf[i]; 
     *it = bs; 
     ++it; 
    } 

    delete [] temp_surf; 
} 

J'ai cette fonction, qui fonctionne bien. Le seul problème est que je ne veux pas appeler le constructeur de copie, car il copie toute la surface, et j'ai seulement besoin de copier le pointeur. Je veux juste utiliser le constructeur par défaut, puis définissez le _surface membre à temp_surface [i], comme ceci:Comment éviter d'appeler le constructeur de copie avec des itérateurs d'insertion

for(int i=0; i<surface_count; ++i) 
{ 
    it->_surface = temp_surf[i]; 
    ++it; 
} 

qui fonctionne pour itérateurs normal, mais pas pour les itérateurs d'insertion. Comment puis-je le réparer pour travailler pour les deux?

+0

Un adaptateur standard 'insert_iterator' est défini pour appeler' insert' du conteneur, qui, à son tour, est défini pour utiliser un constructeur de copie - IOW, 'insert_iterator' _must_ utilise une copie ctor, selon la norme. Vous aurez donc besoin de définir un adaptateur différent qui réduira la quantité de copie (vous aurez probablement toujours besoin de copier-construire au moins un élément nouvellement construit par défaut, si vous voulez utiliser l'insert d'un conteneur sous-jacent) méthode!). –

+0

@Alex - J'ai eu une idée, mais je ne sais pas comment le faire. Je pourrais créer un objet par défaut (_surface = NULL). Puis ajoutez cela au conteneur. Le constructeur de copie dans ce cas serait juste de définir _surface à NULL. Ensuite, après le fait, je pourrais définir le membre de l'objet dans le conteneur. Mais encore une fois, je ne peux pas obtenir cela pour travailler avec des itérateurs d'insertion. Savez-vous comment faire cela? –

+0

@user, l'implémentation standard de l'adaptateur 'insert_iterator' incrémente le pointeur d'insertion dans' operator = ', donc, encore une fois, vous ne pouvez pas le faire ** avec cet adaptateur spécifique **: vous devez implémenter _your propre_ l'adaptateur de l'itérateur à la place. –

Répondre

1

Vraiment ce que vous voulez est un mouvement InputIterator à utiliser avec l'insertion OutputIterator. Puisque cela n'existe pas en C++ 03, il doit y avoir un moyen alternatif de signaler qu'un mouvement "superficiel", et non une copie "profonde", est souhaité. Un indicateur d'état simple dans l'objet lui-même ne fonctionnera pas, car l'implémentation est autorisée à copier l'objet autour aléatoirement avant de le mettre réellement dans le conteneur. (Par souci d'optimisation, vous savez que ce ne sera pas le cas, mais c'est bien de ne pas s'inquiéter des builds de débogage.)

En haut de la tête, cela ressemble à un job pour un allocateur personnalisé. L'allocateur par défaut copy-construit à l'aide de placement new; vous pouvez définir un autre constructeur et l'appeler en utilisant le placement new à la place.

template< typename T > 
struct move_traits { 
    typedef T must_copy_type; // does not exist in specializations 
}; 

template< typename T > 
struct move_if_possible_allocator 
    : std::allocator<T> { 
    typedef move_traits<T> traits; 

     // SFINAE selects this function if there is a specialization 
    void construct(typename traits::may_move_type *obj, T &value) { 
     new(obj) T(); // default construct 
     traits::move_obj(*obj, value); // custom routine 
    } 

     // SFINAE selects this function if traits is the base template 
    void construct(typename traits::must_copy_type *obj, T const &value) { 
     new(obj) T(value); // copy construct (fallback case) 
    } 

    // define rebind... exercise for the reader ;v) 
}; 

template<> 
struct move_traits<BlitSurface> { 
    typedef T may_move_type; // signal existence of specialization 
    static void move_obj(BlitSurface &out, BlitSurface &in) { 
     // fill out and clear in 
    } 
} 

Bien sûr, il est tout à fait bien d'ajouter à l'état BlitSurface à désactiver mouvement par move_obj, si certains objets sont en fait copiés dans le récipient.

+0

Votre code est grec pour moi, mais je comprends votre explication. J'ai évité de traiter avec les allocateurs jusqu'à présent, je suppose qu'il est temps d'apprendre à leur sujet. Je ne serai pas en mesure de l'appliquer efficacement maintenant, mais vous m'avez indiqué dans la bonne direction. Merci. –

0

Il est mentionné qu'un constructeur de copie est appelé. Dans l'exemple fourni, il semble que le conteneur soit probablement défini pour contenir BlitSurface. Quelque chose comme std :: vecteur < BlitSurface>. Ceci est une supposition de ma part des lignes suivantes:

BlitSurface bs; 
    bs._surface = temp_surf[i]; 
    *it = bs; 

Ma compréhension est que tous les conteneurs de std feront une copie sur insert. A partir de là, vous pouvez utiliser les objets dans le conteneur par référence. Si vous ne voulez pas que le constructeur de copie soit appelé sur BlitSurface, je suggère que le conteneur stocke un pointeur vers BlitSurface. De cette façon, lorsque le conteneur fait sa copie sur insérer l'objet dont il fait réellement une copie est un pointeur (pas l'objet BlitSurface pointé vers).

BlitSurface* bs = new BlitSurface; 
    bs->_surface = temp_surf[i]; 
    *it = bs; 

Gardez à l'esprit que cette approche attribue le tas (ie nouveau) si la mémoire devra supprimer explicitement plus tard ou un certain type de pointeur intelligent peut être utilisé dans le récipient pour prendre soin de la suppression (std :: vector < boost :: shared_ptr < BlitSurface>>).

Questions connexes