2011-09-16 18 views
7

Ho 2 classi e uno di loro ha map<string, vector<string> > Voglio poterlo usare in un'altra classe. Ecco il mio codice:Modo corretto per restituire stl map per riferimento/Questo comportamento è ben definito?

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; 
} 

è il modo tornai riferimento alla mappa in class a corretta? Ha funzionato, ma voglio solo confermare se è stato fatto correttamente/ho avuto fortuna/altri commenti sul codice.

Grazie per il vostro aiuto.

+2

digitare typedef della mappa per ridurre la ripetizione – Rookie

+0

Per cosa si dispone di 'b'? Questo è C++, puoi avere funzioni gratis! – sbi

+0

@Rookie, buona idea, grazie! Riposa tutto ok? –

risposta

11

Se non si desidera cambiare la mappa in b::test(), non si dovrebbe fare una copia di esso:

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

mie obiezioni:

  1. Maggiore: a::get() dovrebbe essere const:

    const map<string, vector<string> > & get() const // note the const at the end 
    
  2. Minore: vorrei cr mangia un alias per il tipo di mappa usando typedef.

    typedef map<string, vector<string> > my_map_t; 
    
  3. minore: non riesco a vedere a tutto quello che è per b.

Alla luce di questi, il mio codice sarebbe simile a questa:

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

grazie. Ho capito ora. Non dovrebbe essere - const my_map_t & m = obj.get() (nella funzione test?) –

+0

risolto un po 'di codice. – iammilind

+1

@iammilind: Grazie per il fissaggio. Avrei davvero dovuto provare a compilare questo. ': (' Scusa, @Ian. – sbi

2

Sì, questo è il modo corretto per restituire un riferimento a un oggetto costante.

Tuttavia, nella funzione test in cui si riceve il riferimento restituito, il lato sinistro non è un riferimento. Ciò significa che stai effettivamente creando una copia dell'intera mappa in questa funzione. Un semplice cambiamento risolvere questo problema, e quindi la funzione test diventa zero copia:

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

Correggere, e se posso aggiungere: Se vuoi veramente fare una copia, restituire per valore è probabilmente più veloce. – daramarak

+0

@daramarak: in che modo sarebbe più veloce? è * forzare * il chiamante a fare una copia, se vuole una copia, tornare con riferimento const è sempre la cosa migliore, ma come tutti mi suggeriscono, dubito che voglia davvero fare una copia: – tenfour

+0

@tenour: daramarak potrebbe avere ragione, comunque: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – sbi

1

E 'corretto, ma si dovrebbe utilizzare un riferimento per memorizzare il risultato di obj.get(), come accennato in precedenza. Sarebbe stato corretto se avresti fatto qualcosa di simile:

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

perché, in questo caso, sarà m non esiste più dopo foo() completa l'esecuzione.

0

Invece di rispondere direttamente alla tua domanda, lascia che ti mostri un esempio molto semplice. Considera una semplice classe A con un doppio come membro privato.

class A{ 

private: 

    double a; 

public: 

    A(double _a); 

    double 
    get_a(); 

    double& 
    get_aref(); 

    const double& 
    get_aconstref(); 

}; 

L'implementazione di quella classe. Molto semplice

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; 
} 

Ora consente di accedere al programma principale che utilizza la classe 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; 
} 

Così si può fare solo una
const double& aconstref = ainst.get_aconstref();
e non
double& aconstref = ainst.get_aconstref();
se un metodo di una classe restituisce uno dei membri della classe di tipo T nella forma const T &, vuol dire che non vuole che il chiamante cambi quel membro. Nell'esempio sopra, T è un doppio. Sostituisci una std :: map nella posizione di nits e la stessa logica vale. Spero che sia abbastanza esplicativo. Se si rimuovono le due righe commentate, il compilatore si lamenta poiché si sta tentando di modificare tale riferimento.

Problemi correlati