2013-04-19 2 views
8

Я пытаюсь создать метод класса, который вернет std :: vector, и я немного смущен о наилучшем способе сделать это.Возврат std :: vector - правильный подход

подход я использовал, чтобы определить следующий метод:

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

и в методе выделения нового зЬй :: вектор, который я заполняю данными. Я возвращаю указатель на это, т.е.

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 - это итератор, определенный классом).

В моей main.cpp, я сделал следующее:

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

Я знаю, что с этим подходом, я собираюсь получить оборванный указатель, если я удалить указатель в коде main.cpp , так что это уже немного «опасно». Каков наилучший способ вернуть новый метод std :: vector из метода класса?

Спасибо, ребята Пит

+0

Зачем вам нужно что-либо возвращать? Создайте интерфейс 'BinsProcessor' и попросите' Frequency' обработать бункеры с помощью 'CustomBinsProcessor'. –

ответ

15

Самый лучший способ, чтобы вернуться к значению:

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

Тогда вы бы использовать функцию, как это:

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

Компилятор, вероятно, использовать RVO и не выполнять копии. Если вы используете C++ 11, то перемещение семантики гарантирует, что копии не будут выполнены.

+1

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

+1

@MSalters да, это лучший способ для итерации карты. Тем не менее, OP задает конкретно о семантике возврата, и использование цикла, основанного на диапазонах, здесь не имеет значения. – mfontanini

+0

Справедливая точка. Подумав об этом, я также добавлю 'rtnVec.reserve (_mapFreq.size())'. Опять же, не влияет на тип возврата напрямую, но он устраняет некоторые из копий, которые вы понесли при заполнении 'rtnVec'. – MSalters

4

Возврат по значению

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

    // ... 

    return rtnVec; 
} 

Однако, если вы хотите вернуться к указателю, вы можете использовать смарт-указатели:

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

    //... 

    return rtnVec; 
} 
+0

Если семантика перемещения не используется, возврат по значению приведет к глубокой копии, которая далека от оптимальной. – dtech

+3

@ddriver Как в дизайне OP, так и в этом сообщении оба RVO будут выполняться неявно, а копирование должно выполняться на вызывающем сайте. В C++ 11 близкие варианты их кода будут либо продолжаться до 'RVO', либо неявно« перемещаются ». – Yakk

4

Если вы хотите, чтобы избежать копий/повисшие указатели/..., другой способ просто передать свой std::vector по ссылке к методу:

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

Вам просто нужно то для его определения:

std::vector<double> myBins; 
myFreq3->GetBins(myBins); 
Смежные вопросы