Зачем использовать ссылку в качестве итератора - PullRequest
2 голосов
/ 31 мая 2019

Я узнал об emplace () в std :: vector и наткнулся на этот код:

// vector::emplace
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector = {10,20,30};

  auto it = myvector.emplace ( myvector.begin()+1, 100 );
  myvector.emplace ( it, 200 );
  myvector.emplace ( myvector.end(), 300 );

  std::cout << "myvector contains:";
  for (auto& x: myvector)
    std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

Мне интересно, почему в цикле for они используют ссылку auto & x вместо простой копии, Я пытался без & и он работал так же, это защита, чтобы избежать копирования или трюк производительности?

Ответы [ 2 ]

3 голосов
/ 01 июня 2019

Другое отличие между auto и auto& в этом контексте заключается в том, что auto& позволит вам изменить значение в векторе.Это может быть нежелательной ошибкой, ожидающей своего появления.В идеале, если вы собираетесь использовать ссылку только для чтения, вы должны взять константную ссылку: const auto &

Преимущество использования ссылки, когда вектор содержит объекты, которые являются более значительными, чем просто числовой или указательТип это не будет скопировать весь объект во временный.Если объект имеет какую-либо глубокую семантику копирования или, возможно, является shared_ptr, тогда могут быть значительные издержки, которые полностью исключаются.

Для основного типа копия обычно очень быстрая, поэтому предпочтительна одна копия, новы можете ожидать, что оптимизатор компилятора сделает «правильную вещь», если его попросят сослаться на фундаментальную, а затем использовать эту ссылку много раз, поэтому для программирования шаблонов вы должны предпочесть const-ref над копией, чтобы сохранить код простым, когда вы нене знаю тип.

1 голос
/ 31 мая 2019

Это так же просто, как вы сказали, это будет копия. Так что это действительно трюк с производительностью, но для int он не будет быстрее, он может быть даже медленнее. Но если бы у вас было std::vector<std::string> с миллионами элементов, это имело бы большое значение. Вы можете попробовать это сами.

Но это необходимо, если вы хотите изменить содержимое итерированного контейнера. Без ссылки вы бы изменили копию, а не элемент внутри контейнера. Разницу можно увидеть здесь:

std::vector<int> numbers1 = {1,2,3,4};
std::vector<int> numbers2 = {1,2,3,4};
for(auto& x: numbers1) ++x;
for(auto x: numbers2) ++x;
assert(numbers1!=numbers2); // True

Также я бы рекомендовал использовать auto&& вместо auto&, потому что он будет лучше работать с временными данными, см., Например, этот ответ .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...