2011-09-16 14 views
7

Tengo 2 clases y una de ellas tiene map<string, vector<string> > Quiero poder usar esto en otra clase. Aquí está mi código:Forma correcta de devolver el mapa stl por referencia/¿Está bien definido este comportamiento?

class a 
{ 
    map<string, vector<string> > m; 
    public: 
    const map<string, vector<string> > & get() 
    { 
     return m; 
    } 
}; 

class b 
{ 
    a obj; 
    public: 
    void test() 
    { 
     map<string, vector<string> > m= obj.get(); 
     // and then print 
    } 
}; 

int main(int argc, char ** argv) 
{ 
    b bobj; 
    bobj.test(); 
    return 0; 
} 

es la forma en que regresé referencia a la correspondencia en class a correcta? Funcionó, pero solo quiero confirmar si se hizo correctamente/tuve suerte/cualquier otro comentario sobre el código.

Gracias por su ayuda.

+2

me gustaría escribir el mapa para reducir la repetición – Rookie

+0

¿Para qué tienes 'b'? Esto es C++, ¡puedes tener funciones gratuitas! – sbi

+0

@Rookie, ¡buena idea, gracias! Descansa, todo está bien? –

Respuesta

11

Si no desea cambiar el mapa en b::test(), no se debe hacer una copia de la misma:

const map<string, vector<string> >& m = obj.get(); // note the const & 

Mis objeciones:

  1. Mayor: a::get() debería ser const:

    const map<string, vector<string> > & get() const // note the const at the end 
    
  2. Minor: I would cr eate un alias para el tipo de mapa usando typedef.

    typedef map<string, vector<string> > my_map_t; 
    
  3. Menor: No puedo ver en absoluto lo es para b.

Dadas estas, mi código sería así:

class a 
{ 
    public: 
     typedef map<string, vector<string> > my_map_t; 

     const my_map_t & get() const {return m;} 

    private: 
     my_map_t m; 
}; 

void test(const a& obj) 
{ 
    const a::my_map_t& m = obj.get(); 
    // and then print 
} 

int main() 
{ 
    a obj; 
    test(obj); 
    return 0; 
} 
+0

gracias. Lo entiendo ahora. ¿No debería ser - const my_map_t & m = obj.get() (en la función de prueba?) –

+0

corrigió algún código. – iammilind

+1

@iammilind: Gracias por arreglarlo. Realmente debería haber intentado compilar esto. ': ('Lo siento, @Ian. – sbi

2

Sí, esa es la forma correcta para devolver una referencia a un objeto constante.

Sin embargo, en su función test donde recibe la referencia devuelta, el lado izquierdo no es una referencia. Eso significa que realmente creará una copia del mapa completo en esta función. Un simple cambio solucionará ese problema, y ​​entonces la función se convierte en cero test copia:

void test() 
{ 
    map< string, vector<string> > const & m = obj.get(); 
    // and then print 
} 
+0

Correcto, y si pudiera agregar: si realmente quiere hacer una copia, el valor de retorno es probablemente más rápido. – daramarak

+0

@daramarak: ¿de qué forma sería más rápido? Todo lo que haría es * forzar * a la persona que llama a hacer una copia. Si él quiere una copia, regresar por const reference sigue siendo lo mejor. Pero como todos insinúan, dudo que realmente quiera hacer una copia. – tenfour

+0

@tenour: daramarak podría estar en lo correcto, though: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – sbi

1

Es correcto, pero se debe utilizar una referencia para almacenar el resultado de obj.get(), como se mencionó anteriormente. Hubiera sido incorrecta si hubiera hecho algo como esto:

const map< string, vector<string> >& foo() 
{ 
    map< string, vector<string> > m; 
    // ... 
    return m; 
} 

porque, en este caso, m no existirá más después de foo() completa su ejecución.

0

En lugar de responder directamente a su pregunta, permítame mostrarle un ejemplo muy simple. Considere una clase simple A que tiene un doble como miembro privado.

class A{ 

private: 

    double a; 

public: 

    A(double _a); 

    double 
    get_a(); 

    double& 
    get_aref(); 

    const double& 
    get_aconstref(); 

}; 

La implementación de esa clase. Muy simple

A::A(double _a): a(_a){ 

}; 

// Getters 
double 
A::get_a() { 
    return a; 
} 

double& 
A::get_aref(){ 
    return a; 
} 

const double& 
A::get_aconstref(){ 
    return a; 
} 

Ahora vamos al programa principal que usa la clase A.

int main(){ 

    A ainst(6.0); 

    double a = ainst.get_a(); 
    std::cout << "a = " << a << std::endl; 
    a++; 
    std::cout << "a+1 = " << a << std::endl; 
    std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl; 

    double& aref = ainst.get_aref(); 
    std::cout << "aref = " << aref << std::endl; 
    aref++; 
    std::cout << "aref+1 = " << aref << std::endl; 

    std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl; 

    const double& aconstref = ainst.get_aconstref(); 
    std::cout << "aconstref = " << aconstref << std::endl; 

// aconstref++; 
// std::cout << "aconstref+1 = " << aconstref << std::endl; 

    std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl; 

    return 0; 
} 

lo que sólo puede hacer un
const double& aconstref = ainst.get_aconstref();
y no
double& aconstref = ainst.get_aconstref();
si un método de una clase devuelve uno de los miembros de la clase de tipo T en la forma const T &, significa que no quiere que la persona que llama cambie ese miembro. En el ejemplo anterior, T es un doble. Sustituye un std :: map en nits place y se mantiene la misma lógica. Espero que sea bastante explicativo. Si elimina las dos líneas comentadas, el compilador se queja porque está intentando cambiar esa referencia.

Cuestiones relacionadas