2016-05-18 2 views
3

У меня есть следующий код:Возвращение вектора по значению в ссылку

std::vector<Info*> filter(int direction) 
{ 
    std::vector<Info*> new_buffer; 
    for(std::vector<Info*>::iterator it=m_Buffer.begin();it<m_Buffer.end();it++) 
    { 
     if(((*it)->direction == direction) 
     { 
      new_buffer.push_back(*it); 
     } 
    } 

    return new_buffer; 
} 

std::vector<Info*> &filteredInfo= filter(m_Direction); 

Может кто-то объяснить, что здесь происходит? Будет ли метод фильтра возвращаться по значению, создайте временный файл и filterInfo никогда не будет уничтожен, потому что его ссылка?

Не уверен, что я правильно понял. В чем разница между filterInfo, являющейся ссылкой и не являющейся в этом случае?

+2

Скомпилирует? Если это вы используете MSVS? – NathanOliver

+0

Да, его Visual Studio 2005 – Kobe

+1

ОК. Обратите внимание, что это нестандартный код. MSVS позволяет это, но это не будет работать на большинстве других компиляторов. – NathanOliver

ответ

6

Ваш компилятор должен пожаловаться на этот код.

Это утверждение:

std::vector<Info*> &filteredInfo= filter(m_Direction); 

это плохая идея, где filter является:

std::vector<Info*> filter(int direction); 

Вы пытаетесь создать ссылку на временный объект. Даже если это удастся с вашим компилятором, это незаконно.

Вы должны использовать:

std::vector<Info*> filteredInfo= filter(m_Direction); 

Его столь же эффективным, как вы хотите. Либо произойдет операция move (C++ 11), либо произойдет Return Value Optimization. Для вашей реализации filter это должно быть RVO на оптимизированных строках (это зависит от качества вашего компилятора).

Однако вы должны заметить, что копируете необработанные указатели в свой вектор, я надеюсь, что у вас есть правильная модель владения? Если нет, я советую вам использовать умный указатель.

+0

Может ли это вызвать утечку памяти? при использовании ссылки на временную? – Kobe

+0

@Kobe Не утечка памяти, но, конечно, UB, если вы используете эту ссылку. –

+0

MSVC (Visual Studio) здесь что-то хорошо определяет, но он действительно зависит от компилятора, а не от стандартов – OMGtechy

2

Вот что происходит:

  1. std::vector<Info*> new_buffer; создает объект локально.
  2. return new_buffer; перемещается new_buffer во временный объект, когда вызывается filter(m_Direction).
  3. Теперь, если вы вызываете std::vector<Info*> filteredInfo= filter(m_Direction);, темперный объект будет перемещен в filteredInfo, поэтому нет ненужных копий, и это самый эффективный способ.
  4. Но если вы звоните std::vector<Info*> &filteredInfo= filter(m_Direction);, то filteredInfo привязан к временному объекту, что является ужасной идеей, и большинство компиляторов будут жаловаться на это.
2

Здесь вы правильно озадачен, потому что есть два независимых странные факты смешивания в:

  • Ваш компилятор позволяет неконстантная ссылка на обязательность временного. Это исторически было ошибкой в ​​компиляторах Microsoft и не разрешено стандартом. Этот код не должен компилироваться.
  • Стандарт, однако, как ни странно, на самом деле позволяет привязывать const ссылки на временные рамки и имеет специальное правило для этого: временный объект не будет немедленно уничтожен (как это было бы нормально), но его жизнь будет продлена до срока службы ссылка.

В коде:

std::vector<int> foo() { 
    std::vector<int> x{1,2,3}; 
    return x; 
} 

int main() { 
    const std::vector<int>& x = foo(); // legal 
    for (auto& item : x) { 
     std::cout << x << std::endl; 
    } 
} 

Причина этого, по-видимому абсурдной правило о связывании константных ссылок на временный является то, что в C++ есть очень общий «шаблон» (1) прохождения константных ссылок вместо значения для параметров, даже если личность не имеет значения. Если объединить это (анти) -pattern с неявным преобразованием, что происходит, является то, что, например:

void foo(const std::string& x) { ... } 

не будет вызываемым с

foo("Hey, you"); 

без специального правила, потому что const char * (дословный) неявно преобразовывается во временный std::string и передается как параметр, связанный с ссылкой на константу.

(1) Образец действительно очень плохой с философской точки зрения, потому что значение является значением, а ссылка является ссылкой: эти два являются логически отличными понятиями. A const reference is not a value and confusing the two can be the source of very subtle bugs. C++, однако, одержим по производительности и, особенно перед семантикой переноса, передавая ссылки на const, считается «умным» способом передачи значений, несмотря на то, что это проблема из-за проблем с продолжительностью жизни и псевдонимов и для усложнения оптимизатора. С современным компилятором передача ссылки должна использоваться только для «больших» объектов, особенно тех, которые не, построенных на лету, которые нужно передать, или когда вас действительно интересует идентификация объекта, а не только значение объекта.

Смежные вопросы