Цикл на основе С++ 11: получить элемент по значению или ссылке на const
Читая некоторые примеры циклов, основанных на диапазонах, они предлагают два основных способа: 1, 2, 3, 4
std::vector<MyClass> vec;
for (auto &x : vec)
{
// x is a reference to an item of vec
// We can change vec items by changing x
}
или
for (auto x : vec)
{
// Value of x is copied from an item of vec
// We can not change vec items by changing x
}
Ну.
Когда нам не нужно менять элементы vec
, IMO, примеры предлагают использовать вторую версию (по значению). Почему они не предлагают то, что const
ссылки (по крайней мере, я не нашел прямого предложения):
for (auto const &x : vec) // <-- see const keyword
{
// x is a reference to an const item of vec
// We can not change vec items by changing x
}
Разве это не лучше? Не избегает ли избыточная копия на каждой итерации, пока она const
?
Ответы
Ответ 1
Если вы не хотите изменять элементы, а также хотите избежать копирования, тогда auto const &
является правильным выбором:
for (auto const &x : vec)
Тот, кто предлагает вам использовать auto &
, неверен. Игнорируйте их.
Вот краткое описание:
- Выберите
auto x
, когда вы хотите работать с копиями.
- Выберите
auto &x
, когда вы хотите работать с оригинальными элементами и можете их изменить.
- Выберите
auto const &x
, когда вы хотите работать с оригинальными элементами и не будете изменять их.
Ответ 2
Если у вас есть std::vector<int>
или std::vector<double>
, тогда просто отлично использовать auto
(со значением copy) вместо const auto&
, так как копирование int
или double
дешево:
for (auto x : vec)
....
Но если у вас есть std::vector<MyClass>
, где MyClass
имеет некоторую нетривиальную семантику копирования (например, std::string
, некоторый сложный пользовательский класс и т.д.), то я бы предложил использовать const auto&
для избегать глубоких копий:
for (const auto & x : vec)
....
Ответ 3
Когда нам не нужно менять элементы vec
, в примерах предлагается использовать первую версию.
Затем они дают неправильное предложение.
Почему они не предлагают то, что const ссылается
Потому что они дают неправильное предложение:-) То, что вы упоминаете, является правильным. Если вы хотите, чтобы наблюдал объект, нет необходимости создавать копию, и нет необходимости иметь ссылку на него const
.
EDIT:
Я вижу ссылки, на которые вы ссылаетесь, приводят примеры итерации по диапазону значений int
или некоторого другого фундаментального типа данных. В этом случае, поскольку копирование int
не дорогое, создание копии в основном эквивалентно (если не более эффективному), имеющему наблюдение const &
.
Это, однако, не в общем случае для пользовательских типов. UDT могут быть дорогими для копирования, и если у вас нет причин для создания копии (например, для изменения извлеченного объекта без изменения исходного), то предпочтительно использовать const &
.
Ответ 4
Я собираюсь быть противоположным здесь и сказать, что нет необходимости в auto const &
в диапазоне, основанном на цикле. Скажите, если вы считаете, что следующая функция глупа (не в своей цели, а в том, как она написана):
long long SafePop(std::vector<uint32_t>& v)
{
auto const& cv = v;
long long n = -1;
if (!cv.empty())
{
n = cv.back();
v.pop_back();
}
return n;
}
Здесь автор создал ссылку на const для v
для использования для всех операций, которые не изменяют v. Это глупо, на мой взгляд, и тот же аргумент может быть использован для использования auto const &
в качестве переменной в диапазоне, основанном на цикле, а не просто auto &
.