2013-04-19 10 views
8

Sto cercando di creare un metodo di classe che restituirà un vettore std :: e sono un po 'confuso sul modo migliore per farlo.Restituire un approccio std :: vector - right

L'approccio che ho usato è quello di definire il seguente metodo:

std::vector<double>* GetBins(void); 

e nel metodo, allocare una nuova std :: vector, che riempio con i dati. Sto tornando un puntatore a questo cioè.

std::vector<double>* Frequency::GetBins(void) { 
    std::vector<double> *rtnVec = new std::vector<double>(); 
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); _itMap++) { 
     rtnVec->push_back((*_itMap).first); 
    } 
    return rtnVec; 
} 

(_itMap è un iteratore classe definita).

Nel mio main.cpp, ho fatto quanto segue:

std::vector<double>* myBins; 
myBins = myFreq3->GetBins(); 
delete myBins; 

So che con questo approccio, ho intenzione di ottenere un puntatore penzoloni a meno che non posso cancellare il puntatore nel codice main.cpp , quindi è già un po 'pericoloso'. Qual è il modo migliore per restituire un nuovo std :: vector da un metodo di classe?

Grazie ragazzi Pete

+0

Perché è necessario restituire qualcosa? Crea un'interfaccia 'BinsProcessor' e chiedi 'Frequenza' per elaborare i bin con il tuo' CustomBinsProcessor'. –

risposta

15

Il modo migliore è quello di restituire per valore:

std::vector<double> Frequency::GetBins() { 
    std::vector<double> rtnVec; 
    rtnVec.reserve(_mapFreq.size()); // reserve enough size, no reallocations 
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); ++_itMap) { 
     rtnVec.push_back(_itMap->first); 
    } 
    return rtnVec; 
} 

Allora devi usare la funzione come questa:

std::vector<double> myBins = myFreq3->GetBins(); 
// no need for delete! 

il compilatore probabilmente l'uso RVO e non eseguire alcuna copia. Se stai usando C++ 11, spostare la semantica assicurerà che non vengano eseguite copie.

+1

Oppure 'for (auto && elem: _mapFreq) {rtnVec.push_back (elem.first); } ' – MSalters

+1

@MSalters yes, questo è un modo migliore per iterare la mappa. Tuttavia, l'OP sta chiedendo specificatamente la semantica di ritorno, e l'uso di un loop per il ciclo non fa alcuna differenza qui. – mfontanini

+0

Punto giusto. Pensandoci, aggiungerei anche un 'rtnVec.reserve (_mapFreq.size())'. Di nuovo, non influenza direttamente il tipo di ritorno, ma elimina alcune delle copie che dovresti sostenere durante il riempimento di 'rtnVec'. – MSalters

4

ritorno per valore

std::vector<double> Frequency::GetBins(void) { 
    std::vector<double> rtnVec; 

    // ... 

    return rtnVec; 
} 

Tuttavia, se volete il ritorno dal puntatore, è possibile utilizzare puntatori intelligenti:

std::unique_ptr<std::vector<double>> Frequency::GetBins(void) { 
    std::unique_ptr<std::vector<double>> rtnVec(new std::vector<double>()); 

    //... 

    return rtnVec; 
} 
+0

A meno che non si utilizzi la semantica del movimento, la restituzione per valore causerà una copia profonda, che è ben lungi dall'essere ottimale. – dtech

+3

@ddriver Sia in fase di progettazione dell'OP, sia in questo post, entrambi i termini 'RVO 'si verificano implicitamente e copia elision dovrebbe avvenire sul sito di chiamata. In C++ 11, varianti ravvicinate del loro codice continueranno a 'RVO', o implicitamente a 'move'. – Yakk

4

Se si vuole evitare copie/dangling pointer/..., un altro modo è semplicemente per passare il tuo std::vector con riferimento al metodo:

void Frequency::GetBins(std::vector<double>& bins) { 
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); _itMap++) { 
     bins->push_back((*_itMap).first); 
    } 
} 

Hai solo bisogno quindi per definirlo prima:

std::vector<double> myBins; 
myFreq3->GetBins(myBins);