2013-04-19 17 views
8

Próbuję utworzyć metodę klasy, która zwróci std :: vector, i jestem trochę zdezorientowany co do najlepszego sposobu na zrobienie tego.Zwracanie std :: vector - right approach

Podejście Użyłem jest zdefiniować w następujący sposób:

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

iw sposobie przydzielania nowego std :: vector, którą zapełnić danymi. Wracam do tego wskaźnika.

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 to iterator zdefiniowany przez klasę).

W moim main.cpp, robiłem co następuje:

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

wiem z tym podejściem, mam zamiar dostać dangling wskaźnik chyba usunę wskaźnik w kodzie main.cpp , więc jest już trochę "niebezpieczny". Jaki jest najlepszy sposób na zwrócenie nowego wektora std :: vector z metody klasy?

Dzięki chłopaki Pete

+0

Dlaczego musisz zwrócić wszystko? Stwórz interfejs 'BinsProcessor' i zapytaj' Częstotliwość' o przetwarzanie pojemników za pomocą 'CustomBinsProcessor'. –

Odpowiedz

15

Najlepszym sposobem jest powrót przez wartość:

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

Następnie chcesz korzystać z funkcji takich jak to:

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

Kompilator będzie prawdopodobnie używać RVO i nie wykonuj żadnych kopii. Jeśli używasz C++ 11, to przeniesienie semantyki zapewni, że nie zostaną wykonane żadne kopie.

+1

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

+1

@MSalters tak, to lepszy sposób na iterację mapy. Jednak OP pyta konkretnie o semantykę powracania, a używanie pętli for opartej na odległościach nie ma tu znaczenia. – mfontanini

+0

Punkt targów. Myśląc o tym, dodałbym również 'rtnVec.reserve (_mapFreq.size())'. Ponownie, nie wpływa bezpośrednio na typ zwracany, ale eliminuje niektóre z kopiowania, które ponosisz podczas wypełniania 'rtnVec'. – MSalters

4

Powrót wartością

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

    // ... 

    return rtnVec; 
} 

Jednak jeśli chcesz powrócić przez wskaźnik, można użyć inteligentne kursory:

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

    //... 

    return rtnVec; 
} 
+0

Jeśli nie użyto semantyki przeniesienia, zwracanie przez wartość spowoduje głęboką kopię, która jest daleki od optymalnego. – dtech

+3

@ddriver W obu projektach OP i w tym poście oba "RVO" będą występować w sposób niejawny, a kopiowanie powinno nastąpić w witrynie wywołującej. W C++ 11, bliskie warianty ich kodu będą albo kontynuowały 'RVO', albo będą pośrednio' przenosić'. – Yakk

4

Jeśli chcesz uniknąć kopii/błędnych odwołań/..., inny sposobem jest po prostu zdać std::vector przez odniesienie do metody:

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

wystarczy następnie zdefiniować go wcześniej:

std::vector<double> myBins; 
myFreq3->GetBins(myBins); 
Powiązane problemy