2012-04-25 17 views
7

He probado el siguiente código:¿En qué casos es el constructor de copia llamada, si se copia un recipiente

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor" << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor" << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    std::vector<foo> b(4, foo(4)); 
    //std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 
    return 0; 
} 

consigo

parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    a = b 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 

Sin embargo, si reemplazo std::vector<foo> b(4, foo(4)); por std::vector<foo> b(3, foo(4)); el constructor de copia no es llamado por a = b y la salida es

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 

¿Por qué en este caso no se llama al constructor de copia?

estoy usando g ++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

Esto es realmente extraño ... Incluso es reproducible en ideone ... – RedX

+0

Sooo cool. :) También reproduje eso, aunque no lo creí. –

+0

tal vez el compilador simplemente mueve b a a ya que b no se usa después de la asignación? ¿Has intentado hacer algo con b después de a = b (imprimir, etc.)? – user396672

Respuesta

12

En el primer caso, a necesita para crecer cuando se asigna a la misma, lo que significa que todos sus elementos deben ser reasignados (y por lo tanto destruido y construido).

En el segundo caso, a no necesita crecer, por lo tanto, se utiliza el operador de asignación.

Ver http://ideone.com/atPt9; la adición de un operador de asignación de copia sobrecargado que imprime un mensaje, se obtiene la siguiente para el segundo ejemplo:

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 
copy assignment 
copy assignment 
copy assignment 
+0

Sin embargo, como sabemos, la estructura del 'vector' reserva algunos elementos adicionales, para asegurar velocidades constantes amortizadas de sus operaciones. ¿Por qué entonces el constructor de copia se usa cada vez sin importar los tamaños iniciales de ayb? –

+0

@Boris: no se usa, no importa los tamaños iniciales. El objetivo de la pregunta es que con un par de tamaños iniciales se usa y con otro no. Pruebe 'std :: vector a (3, foo (3)); std :: vector b (4, foo (4)); una reserva (4); a = b; '. Asumiendo que la explicación de Oli es correcta, creo que debería copiar el constructo 3 veces durante la reserva y luego copiar-construir una vez durante la asignación (y copiar-asignar tres veces). Si está en C++ 11, normalmente la 'reserva 'puede moverse en lugar de copiar, pero IIRC un constructor definido por el usuario suprime el constructor de movimiento predeterminado. –

+0

@ BorisStrandjev: utilizando el constructor 'vector (count, T)', la capacidad se establece en 'count' (no estoy seguro si eso es obligatorio por norma, o específico de la implementación). Ver p. http://ideone.com/jngf9. –

3

Se utiliza el operador de asignación.

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor " << m_data << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor " << m_data << " " << other.m_data << std::endl; 
    } 

    foo& operator= (const foo& other){ 
     std::cout << "assignment operator " << m_data << " " << other.m_data << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    //std::vector<foo> b(4, foo(4)); 
    std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 

    for(std::vector<foo>::const_iterator it = a.begin(); it != a.end(); ++it){ 
     std::cout << "a " << it->m_data << std::endl; 
    } 
    for(std::vector<foo>::const_iterator it = b.begin(); it != b.end(); ++it){ 
     std::cout << "b " << it->m_data << std::endl; 
    } 
    return 0; 
} 
parameterised constructor 3 
copy constructor 3 3 
copy constructor 3 3 
copy constructor 3 3 
parameterised constructor 4 
copy constructor 4 4 
copy constructor 4 4 
copy constructor 4 4 
a = b 
assignment operator 3 4 
assignment operator 3 4 
assignment operator 3 4 
a 3 
a 3 
a 3 
b 4 
b 4 
b 4 

respuesta Ver Olis por qué.

+0

@SteveJessop tienes razón, lo corregí. – RedX

Cuestiones relacionadas