2012-05-13 25 views
5

estoy usando la siguiente estructura como una entrada al algoritmo de STL generate_n:de Functor no se mantiene entre llamadas consecutivas a generate_n

struct GenerateNumber {  
    GenerateNumber() : i(0) {} 
    int operator() (void) {   
     return i++; 
    } 
private: 
    int i; 
}; 

un ejemplo para el código que utiliza este funtor es:

std::vector <int> v1 (3); 
std::vector <int> v2 (3); 
GenerateNumber generateNumber; 
std::generate_n (v1.begin(), 3, generateNumber); 
std::generate_n (v2.begin(), 3, generateNumber); 

Sin embargo, el resultado es que ambos v1 y v2 contienen {0,1,2}, en lugar de v2 para contener {3,4,5}. He verificado con un punto de interrupción que el constructor GenerateNumber se llama una sola vez (sé que no tiene sentido que el constructor se llame más de una vez, pero lo revisé de todos modos).

Sé que puedo resolver esto haciendo i estático, pero no entiendo este comportamiento. ¿Cómo es que el valor de i no se mantiene entre llamadas consecutivas?

Respuesta

8

El objeto generador se copia al pasar al generate_n. Trate de usar std::ref, es decir

std::generate_n(v1.begin(), 3, std::ref(generateNumber)); 
std::generate_n(v2.begin(), 3, std::ref(generateNumber)); 

Editar:std::ref Tenga en cuenta que sólo está disponible en C++ 11. Se introdujo en TR1 como std::tr1::ref, y también está disponible en boost como boost::ref.

+0

Usted debería mencionar que 'std :: ref' es C++ 11 (aunque también se menciona en TR1). –

+0

Probablemente tenga que seguir con la solución 'estática', ya que necesito mi código para compilar tanto en VS2010 (que implementa C++ 11) como en GCC 4.4 (que no lo hace). Sin embargo, para completar, cuando uso su sugerencia, obtengo el siguiente error de compilación: 'error C2679: binary '=': no ​​se encuentra operador que tome un operando de la derecha del tipo 'void' (o no hay conversión aceptable)) \t C: \ Archivos de programa (x86) \ Microsoft Visual Studio 10.0 \ VC \ include \ algorithm \t 1581' –

+0

@LucDanton: Gracias por la nota. A veces me olvido, que hubo un tiempo antes de C++ 11. – nosid

3

std::generate_n toma el functor por valor, es decir, hace una copia del mismo. Podría ser que no verificó que se llamaba al constructor de copias .

En ausencia de std::ref, y si su problema se localiza como en tu ejemplo, podría modificar su funtor para tomar una referencia a un conjunto de contadores en el ámbito de las llamadas a std::generate_n:

struct GenerateNumber {  
    GenerateNumber (int& i) : struct GenerateNumber {  
    GenerateNumber() : i(0) {} 
    int operator() (void) {   
     return i++; 
    } 
private: 
    int& i; 
}; 

int main() { 
    int counter = 0; 
    std::vector <int> v1 (3); 
    std::vector <int> v2 (3); 
    GenerateNumber generateNumber(counter); 
    std::generate_n (v1.begin(), 3, generateNumber); 
    std::generate_n (v2.begin(), 3, generateNumber); 

} 
+0

Gracias, esa es una solución elegante. –

Cuestiones relacionadas