2010-03-02 6 views
3

Je me demande s'il y a un avantage à obtenir une référence à un vecteur avant d'appeler BOOST_FOREACH ou si un appel de méthode qui renvoie une référence sera automatiquement utilisé? Par exemple, laquelle des deux boucles suivantes sera équivalente à la troisième boucle?BOOST_FOREACH utilisation implicite de référence?

vector<float>& my_method(); 

void main() 
{ 
    // LOOP 1 ------------------------------- 
    vector<float>& temp_vector = my_method(); 
    BOOST_FOREACH(float element, temp_vector) 
     cout << element << endl; 

    // LOOP 2 ------------------------------- 
    vector<float> temp_vector = my_method(); 
    BOOST_FOREACH(float element, temp_vector) 
     cout << element << endl; 

    // Which loop is this one most like? ---- 
    BOOST_FOREACH(float element, my_method()) 
     cout << element << endl; 
} 
+1

Il y a un article formidable sur la mise en œuvre de 'BOOST_FOREACH': http://www.artima.com/cppsource/foreach.html –

Répondre

2

En regardant à travers BOOST_FOREACH folie metaprogramming Je vois que la collection est copiée si elle est

  1. rvalue,
  2. un "proxy léger", que vous pouvez définir pour vos types en se spécialisant boost::foreach::is_lightweight_proxy.

Par conséquent, lvalue est pas copié. Au lieu de cela, son pointeur est considéré comme temporaire.

bit Crucial est la suivante:

# define BOOST_FOREACH_SHOULD_COPY(COL)    \ 
    (true ? 0 : boost::foreach_detail_::or_(  \ 
     BOOST_FOREACH_IS_RVALUE(COL)    \ 
     , BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL))) 

Ensuite, il est utilisé comme l'un des arguments à la fonction qui est utilisée pour évaluer un récipient dans une variable temporaire:

template<typename T> 
inline auto_any<T> contain(T const &t, boost::mpl::true_ *) // rvalue 
{ 
    return t; 
} 

template<typename T> 
inline auto_any<T *> contain(T &t, boost::mpl::false_ *) // lvalue 
{ 
    // Cannot seem to get sunpro to handle addressof() with array types. 
    #if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x570)) 
    return &t; 
    #else 
    return boost::addressof(t); 
    #endif 
} 

Je Boost v1 .38 installé dans mon système.

0

And although BOOST_FOREACH is a macro, it is a remarkably well-behaved one. It evaluates its arguments exactly once, leading to no nasty surprises

donc my_method() ne sera pas appelé plus d'une fois

Références se comporte comme "normaux" variables du point de vue de l'utilisateur, vous pouvez traiter la référence exactement comme si c'était la variable d'origine. Cela ne fait aucune différence pour la boucle foreach.

Les deux boucles sont donc équivalentes.

+0

ne porte pas sur la partie de référence de la question que je –

+0

mis à jour la réponse –

+0

toujours pas En répondant vraiment à la question de base, le résultat de l'appel de méthode doit être stocké dans une variable temporaire ... en la laissant à la macro pour décider de cela, sera-t-elle stockée dans une référence? ou le résultat sera-t-il copié dans un nouveau vecteur (entraînant une pénalité de performance dans les processus) - voir la question mise à jour. –

4

Un test rapide montre que la fonction est appelée une fois et qu'aucune copie n'est effectuée en relation avec BOOST_FOREACH.

#include <vector> 
#include <iostream> 
#include <boost/foreach.hpp> 

struct X 
{ 
    X() {} 
    X(const X&) { std::cout << "copied\n"; } 
}; 

std::vector<X> vec(2); 

//std::vector<X> method() 
std::vector<X>& method() 
{ 
    std::cout << "returning from method\n"; 
    return vec; 
} 

int main() 
{ 
    BOOST_FOREACH(const X& x, method()) {} 
} 
+0

Merci pour l'excellent code d'exemple, si @Checkers n'avait pas publié d'extraits de la métaprogrammation de boost réelle, je vous aurais donné la réponse :) –