Тип переменной цикла for
От: Lanjeron32  
Дата: 20.01.19 19:06
Оценка:
Привет всем, у меня такой вопрос. Есть обычный vector<int> и нужно просто вывести на консоль его элементы.

vector<int> test = {1, 2, 3, 4, 5};

for (int t: test){ 
        cout << t << " ";
    }

В цикле for вместо int часто указывают auto, тогда компилятор сам определяет тип переменной t. Но оказывается, вместо int можно также указать ссылку int& — у кого-то я видел такое, и в моем примере это нормально работает. Для надежности я указал const int&, и у меня в данном примере это тоже нормально работает.
Все же, как лучше делать, в каких случаях и почему?
Re: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.01.19 20:01
Оценка: 3 (2) +2
Здравствуйте, Lanjeron32, Вы писали:

L>В цикле for вместо int часто указывают auto, тогда компилятор сам определяет тип переменной t. Но оказывается, вместо int можно также указать ссылку int& — у кого-то я видел такое, и в моем примере это нормально работает. Для надежности я указал const int&, и у меня в данном примере это тоже нормально работает.

L>Все же, как лучше делать, в каких случаях и почему?

Если int, в переменную кладётся копия значения из вектора.

Если int&, то переменная это собственно элемент вектора. Можно при этом заменить её значение. Например, ++t в цикле — увеличит все элементы вектора на 1.

Если const int&, то тоже переменная это элемент вектора, но менять её будет нельзя.

Для int это по сути будет без разницы, если используешь t без изменения — int это просто значение, а его копирование дёшево "как 2 байта переслать" (ну, тут обычно 4, но эффект тот же).
А вот если бы это был объект, копирование которого было бы дорогой операцией — разница была бы в быстродействии.
А если копирование переносит реальное значение — то могло бы дать и разрушение сути содержимого вектора.
Поэтому для чего-то сложного — надо тщательно выбирать, какой вариант применять.

Как привычку по умолчанию для таких итераторов надо брать "const тип&", именно из-за минимизации эффектов.
А другие формы использовать только если уверен в том, что нужны именно они.
The God is real, unless declared integer.
Re[2]: Тип переменной цикла for
От: Lanjeron32  
Дата: 20.01.19 21:05
Оценка: +1
Здравствуйте, netch80, Вы писали:

N>А другие формы использовать только если уверен в том, что нужны именно они.


Спасибо за разъяснение, но хотелось бы выработать для себя практические правила, и в дальнейшем всегда следовать им в таких случаях. Мне думается, что нужно выбрать один из двух вариантов (прошу поправить, если я ошибаюсь).

1. Для vector<int> v всегда использовать for (int t: v), и не заморачиваться с const int&, поскольку выигрыша по сравнению с копированием значения практически нет. То же самое делать для float и double. Однако уже для vector<string> v всегда применять for (const string& s: v). Для сложных пользовательских типов (class, struct) — тем более.

2. Или же вообще не усложнять себе жизнь, а для этого в любых случаях всегда применять for (auto t: v).
Re[3]: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.01.19 22:03
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

N>>А другие формы использовать только если уверен в том, что нужны именно они.

L>Спасибо за разъяснение, но хотелось бы выработать для себя практические правила, и в дальнейшем всегда следовать им в таких случаях. Мне думается, что нужно выбрать один из двух вариантов (прошу поправить, если я ошибаюсь).
L>1. Для vector<int> v всегда использовать for (int t: v), и не заморачиваться с const int&, поскольку выигрыша по сравнению с копированием значения практически нет. То же самое делать для float и double. Однако уже для vector<string> v всегда применять for (const string& s: v). Для сложных пользовательских типов (class, struct) — тем более.

Почти. Не "всегда", а если нет причины делать иначе.

L>2. Или же вообще не усложнять себе жизнь, а для этого в любых случаях всегда применять for (auto t: v).


Нет. Копирования могут что-то сломать и вообще они дороги.
The God is real, unless declared integer.
Re[3]: Тип переменной цикла for
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 21.01.19 02:02
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>2. Или же вообще не усложнять себе жизнь, а для этого в любых случаях всегда применять for (auto t: v).


Тут точно так же надо выбирать между auto, auto& и const auto&.
Ce n'est que pour vous dire ce que je vous dis.
Re: Тип переменной цикла for
От: LaptevVV Россия  
Дата: 21.01.19 02:55
Оценка: 2 (1)
L>
L>vector<int> test = {1, 2, 3, 4, 5};
L>for (int t: test){ 
L>        cout << t << " ";
L>    }
L>

L>Все же, как лучше делать, в каких случаях и почему?
Считай 1 элемент цикла — параметром (как в функциях). И поступай так же, как с параметрами.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Тип переменной цикла for
От: Lanjeron32  
Дата: 21.01.19 06:55
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Считай 1 элемент цикла — параметром (как в функциях). И поступай так же, как с параметрами.


А если цикл будет внутри функции, которая принимает константную ссылку на вектор? Например, такая функция:

void PrintVector(const vector<string>& v) {
    for (... s: v) {
        cout << s << " ";
    }
}


На месте многоточия (…) должно стоять const string& — поскольку 1 элемент цикла надо считать параметром, как в функциях? Или здесь должно быть просто string?
Re[3]: Тип переменной цикла for
От: LaptevVV Россия  
Дата: 21.01.19 07:07
Оценка:
LVV>>Считай 1 элемент цикла — параметром (как в функциях). И поступай так же, как с параметрами.
L>А если цикл будет внутри функции, которая принимает константную ссылку на вектор? Например, такая функция:
L>
L>void PrintVector(const vector<string>& v) {
L>    for (... s: v) {
L>        cout << s << " ";
L>    }
L>} 
L>

L>На месте многоточия (…) должно стоять const string& — поскольку 1 элемент цикла надо считать параметром, как в функциях? Или здесь должно быть просто string?
Ну, сам for можно считать вызовом функции, у которой параметром является первый элемент.
В данном конкретном случае вполне подойдет const string &s
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Тип переменной цикла for
От: _vanger_  
Дата: 21.01.19 07:10
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>
L>void PrintVector(const vector<string>& v) {
L>    for (... s: v) {
L>        cout << s << " ";
L>    }
L>} 
L>


L>На месте многоточия (…) должно стоять const string& — поскольку 1 элемент цикла надо считать параметром, как в функциях?


Да, если хочется избежать копирования. Собственно,
for (... s: v) {
    cout << s << " ";
}

более-менее эквивалентно
for (auto it = v.begin(); it != v.end(); ++it) {
    ... s = *it;
    cout << s << " ";
}

Откуда и следуют ответы на вопросы.
Re: Тип переменной цикла for
От: Igore Россия  
Дата: 21.01.19 08:01
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>Привет всем, у меня такой вопрос. Есть обычный vector<int> и нужно просто вывести на консоль его элементы.


L>
L>vector<int> test = {1, 2, 3, 4, 5};

L>for (int t: test){ 
L>        cout << t << " ";
L>    }
L>

L>В цикле for вместо int часто указывают auto, тогда компилятор сам определяет тип переменной t. Но оказывается, вместо int можно также указать ссылку int& — у кого-то я видел такое, и в моем примере это нормально работает. Для надежности я указал const int&, и у меня в данном примере это тоже нормально работает.
L>Все же, как лучше делать, в каких случаях и почему?

Я привык так писать:
for( const auto& it: test)
{
   cout << it << " ";
}

Иногда кстати встречается еще более интересный вариант
for( const auto && it: test)
{
   cout << it << " ";
}
Re[3]: Тип переменной цикла for
От: rg45 СССР  
Дата: 21.01.19 08:25
Оценка: +3 -1
Здравствуйте, Lanjeron32, Вы писали:

L>2. Или же вообще не усложнять себе жизнь, а для этого в любых случаях всегда применять for (auto t: v).


Как раз из этих соображений — чтобы не усложнять себе жизнь — в качестве универсального варианта лучше бы выбрать "for (const auto& t : v)". Ибо урон от нежелательного копирования может быть существеенно более ощутимый, чем от лишней косвенности. С которой современые оптимизаторы справляются без особого труда.
--
Re[2]: Тип переменной цикла for
От: rg45 СССР  
Дата: 21.01.19 08:33
Оценка: 1 (1) +1
Здравствуйте, Igore, Вы писали:

I>Иногда кстати встречается еще более интересный вариант

I>
I>for( const auto && it: test)
I>{
I>   cout << it << " ";
I>}
I>


Только в этом случае "const" уже является лишним и будет только приводить к ошибкам компиляции. Вообще "auto&&" и "const auto&&" — это две большие разницы. Первый вариант — это так называемая forwarding reference (или, как ее назвали раньше "universal reference"), тогда как второй — просто константная rvalue ссылка.
--
Отредактировано 21.01.2019 8:34 rg45 . Предыдущая версия .
Re[2]: Тип переменной цикла for
От: Lanjeron32  
Дата: 21.01.19 08:43
Оценка:
Здравствуйте, Igore, Вы писали:

I>Иногда кстати встречается еще более интересный вариант

I>
I>for( const auto && it: test)
I>{
I>   cout << it << " ";
I>}
I>


Мне тоже несколько раз уже встречался такой вариант. Это для передачи по константной ссылке rvalue, правильно?

UPD: а, вижу, rg45 на этот вопрос уже ответил.
Отредактировано 21.01.2019 8:48 Lanjeron32 . Предыдущая версия .
Re[3]: Тип переменной цикла for
От: rg45 СССР  
Дата: 21.01.19 08:57
Оценка: 10 (1)
Здравствуйте, Lanjeron32, Вы писали:

L>Мне тоже несколько раз уже встречался такой вариант. Это для передачи по константной ссылке rvalue, правильно?

L>UPD: а, вижу, rg45 на этот вопрос уже ответил.

Чуть более развернуто: конструкция "auto&&" является автоподстраиваемой и может развернуться как в константную lvalue ссылку, так и в неконстантную — в зависимости от константности самого контейнера. Вот только полезность такой гибкости конкретно при пременении внутри циклов range for мне кажется сомнительной. Просто не могу придумать практически полезный пример, когда бы мы не знали, какой контейнер мы обрабатываем, константый или неконстантный.

[Upd]
Конструкция "auto&&" могла бы разворачиваться и в rvalue reference, если бы операции разыменования итераторов страндартных контейнеров возвращали либо по значению, либо rvalue ссылки. Но такого нет в стандартной библиотеке — все эти операции возвращают, by design, только lvalue ссылки — либо константные, либо некостантые. Соответственно и конструкция "auto&&" может развернуться только в lvalue ссылку, либо константную, либо неконстантную. Происходит это примерно так: допустим, операция разыменования неконстантного итератора возвращает неконстантную ссылку "int &". Тогда конструкция "auto &&" сначала разворачивается в промежуточную конструкцию вида: "int & &&". Как бы "rvalue ссылка на lvalue ссылку". Затем эта кострукция, благодаря механизму reference collapsing, появившемуся в C++11, приобретает свою финальную форму: "int&".
--
Отредактировано 21.01.2019 9:19 rg45 . Предыдущая версия .
Re[4]: Тип переменной цикла for
От: Lanjeron32  
Дата: 21.01.19 09:30
Оценка:
Здравствуйте, rg45, Вы писали:

R>Чуть более развернуто: конструкция "auto&&" является автоподстраиваемой и может развернуться как в константную lvalue ссылку, так и в неконстантную — в зависимости от константности самого контейнера. Вот только полезность такой гибкости конкретно при пременении внутри циклов range for мне кажется сомнительной. Просто не могу придумать практически полезный пример, когда бы мы не знали, какой контейнер мы обрабатываем, константый или неконстантный.

Для меня передача rvalue по ссылке, семантика move, все это пока еще довольно сложно. Мне бы сейчас разобраться с тем простым примером, где в функцию передается vector<string>, а в теле функции есть цикл for. В учебном примере я видел, сделано так:

void PrintVector(const vector<string>& v) {
    for (string s: v) {
        cout << s << " ";
    }
}

Как я понял из предыдущих ответов, в цикле for лучше вместо string поставить const string&. Но вопросы у меня еще остаются. Вектор v в функцию передается по константной ссылке, и в теле функции доступен по константной ссылке. Значит, каждый элемент s этого вектора в теле функции тоже доступен по константной ссылке, правильно? Тогда почему автор все же использует string? (между прочим, автор — ведущий разработчик Яндекса. Фамилию называть не буду, но очень сильный специалист).
Re[5]: Тип переменной цикла for
От: rg45 СССР  
Дата: 21.01.19 09:37
Оценка: 2 (1)
Здравствуйте, Lanjeron32, Вы писали:

L>Как я понял из предыдущих ответов, в цикле for лучше вместо string поставить const string&. Но вопросы у меня еще остаются. Вектор v в функцию передается по константной ссылке, и в теле функции доступен по константной ссылке. Значит, каждый элемент s этого вектора в теле функции тоже доступен по константной ссылке, правильно?


Все верно.

L>Тогда почему автор все же использует string? (между прочим, автор — ведущий разработчик Яндекса. Фамилию называть не буду, но очень сильный специалист).


Как я полагаю, просто для упрощения текста примеров. Для учебных примеров такие вопросы оптимизации не являются существенными. Тем более с учетом того, что многие реализации std::string используют технологию "copy on write". Хотя эффект получается прямо противоположный ожидаемому — вместо упрощения у читателей появляются вопросы, вполне закономерные.
--
Re[5]: Тип переменной цикла for
От: B0FEE664  
Дата: 21.01.19 10:25
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>
L>void PrintVector(const vector<string>& v) {
L>    for (string s: v) {
L>        cout << s << " ";
L>    }
L>}
L>

L>Как я понял из предыдущих ответов, в цикле for лучше вместо string поставить const string&.

В общем случае всё ещё может зависеть от того, что потом делают с переменной s.

void PrintVector(const vector<string>& v)
{
    for (string s: v)
    {
        //заменяем все '-' на '+' 
        std::replace(s.begin(), s.end(), '-', '+');
        cout << s << " ";
    }
}
И каждый день — без права на ошибку...
Re[4]: Тип переменной цикла for
От: B0FEE664  
Дата: 21.01.19 10:58
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Конструкция "auto&&" могла бы разворачиваться и в rvalue reference, если бы операции разыменования итераторов страндартных контейнеров возвращали либо по значению, либо rvalue ссылки. Но такого нет в стандартной библиотеке — все эти операции возвращают, by design, только lvalue ссылки — либо константные, либо некостантые.


Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:
template<typename Range, typename Value>
void set_to(Range& range, const Value& value) 
{
    for (auto& x : range)
    { 
        x = value;
    }
}


а не константный цикл изменяет сам вектор:
https://ideone.com/5yoWll

template<typename Range, typename Value>
void set_to(Range& range, const Value& value) 
{
    for (auto x : range)
    { 
        x = value;
    }
}
И каждый день — без права на ошибку...
Re: Тип переменной цикла for
От: lpd Черногория  
Дата: 21.01.19 11:10
Оценка: -2
Здравствуйте, Lanjeron32, Вы писали:

L>Привет всем, у меня такой вопрос. Есть обычный vector<int> и нужно просто вывести на консоль его элементы.

L>Все же, как лучше делать, в каких случаях и почему?

Советую сначала изучать ассемблер, как минимум чтобы представлять что происходит когда исполняется код на C++. И только потом уже заморачиваться на последние стандарты C++, если захочешь.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re: Тип переменной цикла for
От: sergii.p  
Дата: 21.01.19 11:42
Оценка: :)
Здравствуйте, Lanjeron32, Вы писали:

L>Все же, как лучше делать, в каких случаях и почему?


во всех случаях auto&&. Главный аргумент — думать не надо.
Re[5]: Тип переменной цикла for
От: rg45 СССР  
Дата: 21.01.19 12:45
Оценка: 3 (1) +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:


Ну да, это я выпустил из виду. Ну, на этом и все, пожалуй

В связи с этим уместно будет, пожалуй, вспомнить о не менее распространенной рекоммендации никогда не использовать vector<bool>. Как, например, здесь:

https://www.perforce.com/resources/qac/high-integrity-cpp-coding-standard

Standard library

17.1 General



17.1.1 Do not use std::vector<bool>


The std::vector<bool> specialization does not conform to the requirements of a container and does not work as expected in all STL algorithms. In particular &v[0] does not return a contiguous array of elements as it does for other vector types. Additionally, the C++ language standard guarantees that different elements of an STL container can safely be modified concurrently, except for a container of std::vector<bool> type.

--
Отредактировано 21.01.2019 12:58 rg45 . Предыдущая версия . Еще …
Отредактировано 21.01.2019 12:56 rg45 . Предыдущая версия .
Re[6]: Тип переменной цикла for
От: Videoman Россия https://hts.tv/
Дата: 21.01.19 12:53
Оценка: 9 (1) +1
Здравствуйте, rg45, Вы писали:

R>Как я полагаю, просто для упрощения текста примеров. Для учебных примеров такие вопросы оптимизации не являются существенными. Тем более с учетом того, что многие реализации std::string используют технологию "copy on write". Хотя эффект получается прямо противоположный ожидаемому — вместо упрощения у читателей появляются вопросы, вполне закономерные.


Последние требования к интерфейсу std::basic_string фактически запрещают идиому "copy on write", так что начиная с C++11 строки фактически обязаны копироваться. Для строк осталась только small strings optimization, по желанию.
Re[5]: Тип переменной цикла for
От: Videoman Россия https://hts.tv/
Дата: 21.01.19 12:57
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:

BFE>...

Можно не рассматривать, т.к. std::vector<bool> не рекомендуется использовать, именно из-за его кривого дизайна.
Отредактировано 21.01.2019 13:28 Videoman . Предыдущая версия . Еще …
Отредактировано 21.01.2019 13:03 Videoman . Предыдущая версия .
Re[6]: Тип переменной цикла for
От: B0FEE664  
Дата: 21.01.19 14:25
Оценка:
Здравствуйте, Videoman, Вы писали:

BFE>>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:

BFE>>...
V>Можно не рассматривать, т.к. std::vector<bool> не рекомендуется использовать, именно из-за его кривого дизайна.

Интересно. Раньше его не рекомендовали использовать, из-за реализации, а теперь из-за дизайна.
И каждый день — без права на ошибку...
Re: Тип переменной цикла for
От: MasterZiv СССР  
Дата: 21.01.19 14:52
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>Привет всем, у меня такой вопрос. Есть обычный vector<int> и нужно просто вывести на консоль его элементы.


L>
L>vector<int> test = {1, 2, 3, 4, 5};

L>for (int t: test){ 
L>        cout << t << " ";
L>    }
L>

L>В цикле for вместо int часто указывают auto, тогда компилятор сам определяет тип переменной t. Но оказывается, вместо int можно также указать ссылку int& — у кого-то я видел такое, и в моем примере это нормально работает. Для надежности я указал const int&, и у меня в данном примере это тоже нормально работает.
L>Все же, как лучше делать, в каких случаях и почему?

Лучше

for (const auto& t: test)


Подойдёт везде.
Re[7]: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.01.19 14:53
Оценка: +2
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:

BFE>>>...
V>>Можно не рассматривать, т.к. std::vector<bool> не рекомендуется использовать, именно из-за его кривого дизайна.
BFE>Интересно. Раньше его не рекомендовали использовать, из-за реализации, а теперь из-за дизайна.

В данном случае речь об одном и том же.

Какой-то криворукий эконом вместо выделения отдельного bit_vector<> испортил стандартный vector.
В сочетании с "мы говорим vector — подразумеваем массив, говорим array — подразумеваем vector" это выглядит особенно впечатляюще.
The God is real, unless declared integer.
Re[2]: Тип переменной цикла for
От: sergii.p  
Дата: 23.01.19 08:24
Оценка:
а я и не шутил. Программист образца 98 года конечно ставил const & и больше не думал. Но после 11-го года программист задаёт себе извечный вопрос: а можно ли (и надо ли) мне будет перемещать элементы контейнера. Ну для меня решить этот вопрос не так то и легко. Надо сразу взвесить много факторов. И зачастую точно ответить на вопрос иногда не получается. Тогда приходит на помощь auto&&. Я так пишу и даже не останавливаюсь. Откажусь я от перемещения, или, наоборот, буду перемещать: мне уже всё равно — шапка цикла останется неизменной.
Re[3]: Тип переменной цикла for
От: rg45 СССР  
Дата: 23.01.19 08:37
Оценка: 1 (1) +2
Здравствуйте, sergii.p, Вы писали:

SP>а я и не шутил. Программист образца 98 года конечно ставил const & и больше не думал. Но после 11-го года программист задаёт себе извечный вопрос: а можно ли (и надо ли) мне будет перемещать элементы контейнера. Ну для меня решить этот вопрос не так то и легко. Надо сразу взвесить много факторов. И зачастую точно ответить на вопрос иногда не получается. Тогда приходит на помощь auto&&. Я так пишу и даже не останавливаюсь. Откажусь я от перемещения, или, наоборот, буду перемещать: мне уже всё равно — шапка цикла останется неизменной.


А вот здесь тебя ждет засада: переменная цикла, объявленная как auto&& в любом случае будет lvalue ссылкой (если говорить об использовании со стандарными контейнерами), несмотря на значок "&&". Она может оказаться константной ссылкой, а может оказаться неконстантной — в зависимости от константности/неконстантности самого контейнера. Но, в любом случае, это будет lvalue ссылка. Так что перемещать элементы конейнера без явного использования std::move (или развноценного преобразования) тебе все равно не удастся.

https://ideone.com/AFDBwx

#include <vector>

int main()
{
   std::vector<int> v {1, 2, 3};

   for (auto&& e : v)   
   {
         int&& rr = e; // error: cannot bind ‘int’ lvalue to ‘int&&’
   }
}


P.S. Да, за исключением единственного случая — std::vector&lt;bool&gt;
Автор: B0FEE664
Дата: 21.01.19


И даже в гипотетическом случае (какие-то нестандартные контейнеры), если эта переменная цикла каким-то образом окажется настоящей rvalue ссылкой, выражение, составленное из имени этой переменной, все равно будет являться lvalue выражением и также потребует явного преобразования для перемещения:

https://ideone.com/z6n9a7

class MyVectorInt
{
public:    
  
   struct Iterator
   {
         int operator*() const;
         void operator++();
         void operator++(int);
         bool operator == (const Iterator&) const;
         bool operator != (const Iterator&) const;
   };


   Iterator begin() const;
   Iterator end() const;
};

int main()
{
   for (auto&& e : MyVectorInt())
   {
      int&& rr = e;  // error: cannot bind ‘int’ lvalue to ‘int&&’
   }
}
--
Отредактировано 23.01.2019 9:08 rg45 . Предыдущая версия . Еще …
Отредактировано 23.01.2019 9:05 rg45 . Предыдущая версия .
Отредактировано 23.01.2019 8:57 rg45 . Предыдущая версия .
Отредактировано 23.01.2019 8:56 rg45 . Предыдущая версия .
Отредактировано 23.01.2019 8:48 rg45 . Предыдущая версия .
Отредактировано 23.01.2019 8:44 rg45 . Предыдущая версия .
Re[3]: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.01.19 09:02
Оценка: 1 (1) +4
Здравствуйте, sergii.p, Вы писали:

SP> Но после 11-го года программист задаёт себе извечный вопрос: а можно ли (и надо ли) мне будет перемещать элементы контейнера. Ну для меня решить этот вопрос не так то и легко. Надо сразу взвесить много факторов. И зачастую точно ответить на вопрос иногда не получается. Тогда приходит на помощь auto&&. Я так пишу и даже не останавливаюсь. Откажусь я от перемещения, или, наоборот, буду перемещать: мне уже всё равно — шапка цикла останется неизменной.


Вот это и плохо.
Если цикл принципиально предназначен не менять элементы — лучше это обозначить в шапке, чтобы 1) было видно по этому циклу, 2) случайное изменение внутри — ломалось и требовало правки формы цикла.
The God is real, unless declared integer.
Re[4]: Тип переменной цикла for
От: sergii.p  
Дата: 23.01.19 10:27
Оценка:
Здравствуйте, rg45, Вы писали:

Так что перемещать элементы конейнера без явного использования std::move (или развноценного преобразования) тебе все равно не удастся.

я вроде и не писал, что собираюсь перемещать без явного move
Re[8]: Тип переменной цикла for
От: B0FEE664  
Дата: 23.01.19 10:38
Оценка:
Здравствуйте, netch80, Вы писали:

BFE>>>>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:

BFE>>>>...
V>>>Можно не рассматривать, т.к. std::vector<bool> не рекомендуется использовать, именно из-за его кривого дизайна.
BFE>>Интересно. Раньше его не рекомендовали использовать, из-за реализации, а теперь из-за дизайна.

N>В данном случае речь об одном и том же.

Раньше были реализации, где каждый элемент массива std::vector<bool> занимал от одного до 4-х байт.

N>Какой-то криворукий эконом вместо выделения отдельного bit_vector<> испортил стандартный vector.

Пора разрабатывать std::v2:: ...

N>В сочетании с "мы говорим vector — подразумеваем массив, говорим array — подразумеваем vector" это выглядит особенно впечатляюще.

array — это std::array
И каждый день — без права на ошибку...
Re[5]: Тип переменной цикла for
От: rg45 СССР  
Дата: 23.01.19 10:40
Оценка:
Здравствуйте, sergii.p, Вы писали:


SP>я вроде и не писал, что собираюсь перемещать без явного move


В таком случае я не понял, как объявление переменной цикла как auto&&, может помочь решить извечный вопрос:

Но после 11-го года программист задаёт себе извечный вопрос: а можно ли (и надо ли) мне будет перемещать элементы контейнера.

--
Re[9]: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.01.19 11:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

N>>В данном случае речь об одном и том же.

BFE>Раньше были реализации, где каждый элемент массива std::vector<bool> занимал от одного до 4-х байт.

Ну если естественный bool занимает "от одного до 4-х байт", то так и должно быть в несжатом хранилище. А сжатое должно идти отдельным пунктом.

N>>Какой-то криворукий эконом вместо выделения отдельного bit_vector<> испортил стандартный vector.

BFE>Пора разрабатывать std::v2:: ...

Ага, и допускать 15 лет на адаптацию под него

N>>В сочетании с "мы говорим vector — подразумеваем массив, говорим array — подразумеваем vector" это выглядит особенно впечатляюще.

BFE>array — это std::array

Я про то, что — цитирую Страуса —

One could argue that valarray should have been called vector because it is a traditional mathematical vector and that vector (§16.3) should have been called array. However, this is not the way the terminology evolved. A valarray is a vector optimized for numeric computation, a vector is a flexible container designed for holding and manipulating objects of a wide variety of types, and an
array is a low-level, built-in type.

"Извините, мы тут напутали в терминологии, живите теперь с этим".
The God is real, unless declared integer.
Re[6]: Тип переменной цикла for
От: sergii.p  
Дата: 23.01.19 14:51
Оценка:
Здравствуйте, rg45, Вы писали:

R>В таком случае я не понял, как объявление переменной цикла как auto&&, может помочь решить извечный вопрос


да, может не очень хорошо объяснил. Короче, идея в том, что при написании шапки цикла я вообще отключаю мозги
for(auto&& el: array) { }

меня не интересует, собираюсь ли я менять элементы или перемещать их, либо мне нужны только константные методы. Ответы на эти вопросы будут позже. Короче, универсальная ссылка на то и универсальная, чтобы съесть всё. И этот подход облегчает задачи рефакторинга. Потому что часть кода (шапка цикла) работает в любом случае независимо от внешней обстановки.
Re[6]: Тип переменной цикла for
От: cures Россия cures.narod.ru
Дата: 23.01.19 16:44
Оценка:
Здравствуйте, rg45, Вы писали:

R>В связи с этим уместно будет, пожалуй, вспомнить о не менее распространенной рекоммендации никогда не использовать vector<bool>. Как, например, здесь:


Дурацкая рекомендация. Нам нога не нужна — и вы свою не используйте.
Ежу понятно, что раз минимальная адресуемая железом единица — байт, то к битам конкурентно ходить не получится. Для конкурентности юзайте байт. Это ограничение железа.
А булев массив признака простоты на числа до 2^32 займёт 256 метров при нынешней, нормальной реализации, и 2 гига при байтовой, всем пофигу?
Нахрена мне той дурацкой конструкцией получать "непрерывный массив" бит — тем более не ясно. У меня сам vector<bool> уже фактически таковым является.
Похоже, программисты на бейсике и питоне взялись писать рекомендации плюсовикам. Ну, удачи им.
Re[7]: Тип переменной цикла for
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.01.19 17:47
Оценка:
Здравствуйте, cures, Вы писали:

R>>В связи с этим уместно будет, пожалуй, вспомнить о не менее распространенной рекоммендации никогда не использовать vector<bool>. Как, например, здесь:

C>Дурацкая рекомендация. Нам нога не нужна — и вы свою не используйте.

Проблема в том, что можно изменить где-то в другом месте тип foo_t на тип bar_t, до этого независимо изменить bar_t, например, с int на bool, а от этого изменится реализация vector<bar_t>.
Именно поэтому надо было не переопределять vector<bool>, а делать отдельный тип, или шаблонный контейнер плотной упаковки типа bit_vector<N> для элементов по N бит.

C>Ежу понятно, что раз минимальная адресуемая железом единица — байт, то к битам конкурентно ходить не получится. Для конкурентности юзайте байт. Это ограничение железа.


1. Ежу непонятно, потому что логический переход bool -> бит изначально не был предусмотрен.
2. Вообще-то такого ограничения нет. X86: lock cmpxchg, lock bts, и так далее. Но к этому надо готовиться явно, а не ломать vector.

C>А булев массив признака простоты на числа до 2^32 займёт 256 метров при нынешней, нормальной реализации, и 2 гига при байтовой, всем пофигу?


Задача массива признака простоты в таком виде, ещё и конкурентно... это кому ж такое постоянно нужно, и почему от этого должны страдать остальные пользователи C++?

C>Нахрена мне той дурацкой конструкцией получать "непрерывный массив" бит — тем более не ясно. У меня сам vector<bool> уже фактически таковым является.

C>Похоже, программисты на бейсике и питоне взялись писать рекомендации плюсовикам. Ну, удачи им.

Вполне себе на плюсах. Но это не означает, что инструмент — неприкосновенная корова.
The God is real, unless declared integer.
Re[7]: Тип переменной цикла for
От: rg45 СССР  
Дата: 23.01.19 19:39
Оценка:
Здравствуйте, cures, Вы писали:

R>>В связи с этим уместно будет, пожалуй, вспомнить о не менее распространенной рекоммендации никогда не использовать vector<bool>. Как, например, здесь:


C>Дурацкая рекомендация. Нам нога не нужна — и вы свою не используйте.


Ну хорошо, давай сейчас не будем об этом спорить. Все-таки, сейчас в фокусе внимания несколько другие вещи. А исключения, как известно, только подтверждают правила.
--
Re[7]: Тип переменной цикла for
От: Videoman Россия https://hts.tv/
Дата: 24.01.19 09:09
Оценка: +2
Здравствуйте, sergii.p, Вы писали:

SP>да, может не очень хорошо объяснил. Короче, идея в том, что при написании шапки цикла я вообще отключаю мозги


Отключать мозги при программировании, а особенно на С++, не лучший подход. Упрощая себе работу при написании вы сильно усложняете ее тому кто будет читать ваш код и не раз, особенно, если после ":" в цикле стоит функция и сразу не понятно какой тип контейнера она возвращает и какой тип элементов этого контейнера. Auto вводился, в основном, для упрощения работы с "трехэтажными" шаблонами, для случая где понятно или не важно какой используется тип. Злоупотребляя auto вы лишаете себя и компилятор дополнительной возможности контроля на уровне типов. Из этой же серии: я отключаю голову и везде не пишу const, ни при объявлении переменных, ни при объявлении методов класса, и все работает!
Отредактировано 24.01.2019 12:38 Videoman . Предыдущая версия . Еще …
Отредактировано 24.01.2019 9:13 Videoman . Предыдущая версия .
Re[8]: Тип переменной цикла for
От: cures Россия cures.narod.ru
Дата: 24.01.19 18:49
Оценка:
Здравствуйте, netch80, Вы писали:

N>Проблема в том, что можно изменить где-то в другом месте тип foo_t на тип bar_t, до этого независимо изменить bar_t, например, с int на bool, а от этого изменится реализация vector<bar_t>.


Так именно от этого сценария указанная рекомендация никак не спасает. Даже если ей следовали, и сознательно нигде не пользовались вектором булов, а потом не со зла заменили где-то инт на бул, внезапно, тихо и незаметно оный вектор всё равно оказывается в проекте. И, может быть, летят тонны варнингов с еррорами, если кто-то пользовался той фигнёй, либо просто выдаётся фигня, если кто-то тупо полез менять значения конкурентно.
Тогда уж надо рекомендовать вообще не пользоваться вектором, но идиотизм подобной рекомендации оказался очевидным даже для авторов.

N>Именно поэтому надо было не переопределять vector<bool>, а делать отдельный тип, или шаблонный контейнер плотной упаковки типа bit_vector<N> для элементов по N бит.


Полностью с Вами согласен. И ещё хорошо бы добавить туда приятных (быстрых) операций типа найти следующий нулевой (ненулевой) бит, поставить, очистить или свопнуть биты с такого-то по такой-то, возможно, ещё какие-то. Из-за их отсутствия иногда приходится самому имплементить.
Беда этой рекомендации не в том, что она даёт нам совет по написанию стандартной библиотеки. Тогда бы мы её просто проигнорировали, ибо мы ту библиотеку не пишем. Она просто требует, чтобы мы не пользовались тем, что есть, при том, что другого приемлемого для этих целей нет.
Единственная осмысленная надежда, которая могла двигать такими советчиками — что все их послушаются, перестанут пользоваться вектором булов, Страуструп и Степанов это увидят, заплачут и всё переделают. В этом я и пожелал им удачков.

Таким образом, данная рекомендация никак не помогает, когда нужно, и вредит, когда не нужно. Поэтому я и назвал её дурацкой.

И ещё, не надо темплэйтить его по N, это тогда получится array. От вектора мне таки может понадобиться изменение размера, либо использование с размером, известным только на рантайме.
Идея вектора слишком хороша, чтобы её так просто выбрасывать.

C>>Ежу понятно, что раз минимальная адресуемая железом единица — байт, то к битам конкурентно ходить не получится. Для конкурентности юзайте байт. Это ограничение железа.


N>1. Ежу непонятно, потому что логический переход bool -> бит изначально не был предусмотрен.


Не понял утверждения. bool — тип для хранения логического значения, бит — единица информации, как раз под одно логическое значение. Кем и когда не была предусмотрена их связь?

N>2. Вообще-то такого ограничения нет. X86: lock cmpxchg, lock bts, и так далее. Но к этому надо готовиться явно, а не ломать vector.


Если они будут медленнее, чем в простой нынешней реализации, то это надо таки выносить в другой класс. Мы не должны платить за то, чем не пользуемся.

N>Задача массива признака простоты в таком виде, ещё и конкурентно... это кому ж такое постоянно нужно, и почему от этого должны страдать остальные пользователи C++?


В том-то и дело, что конкурентно как раз мне не нужно. Максимум оттуда будут параллельно читать, что никому не повредит. А мне запрещают ковыряться в носу этим пользоваться, ссылаясь на мифический конкурентный доступ и проблемы при нём.
Ну и это всего лишь один из первых вспомнившихся примеров, мало ли когда нужно много булов. А вот пользователи питона, которым пофигу, сколько что занимает памяти, полезшие зачем-то в плюсы, должны страдать.

N>Вполне себе на плюсах. Но это не означает, что инструмент — неприкосновенная корова.


Инструмент есть, переделывать его никто не собирается. Авторы инструмента, очевидно, послали этих деятелей довольно далеко, и, может быть, ещё как-то грубо с ними обошлись. Теперь эти советчики просто пакостят авторам, отговаривая пользователей этим инструментом пользоваться?
Re[6]: Тип переменной цикла for
От: YuriV  
Дата: 26.01.19 07:54
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, B0FEE664, Вы писали:


BFE>>Есть. Есть распространённый пример: std::vector<bool> для которого ссылки не компилируются:


R>Ну да, это я выпустил из виду. Ну, на этом и все, пожалуй


R>В связи с этим уместно будет, пожалуй, вспомнить о не менее распространенной рекоммендации никогда не использовать vector<bool>. Как, например, здесь:


vector<bool> это, как раз, пример когда специализация сужает область применения обобщённой сущности, что есть нонсенс, а значит ошибка архитектуры. Если к специализации нужно писать отдельную рекомендацию по применению, то от такой специализации нужно отказаться. Как здесь правильно сказали следует использовать отдельный тип.
Re[7]: Тип переменной цикла for
От: rg45 СССР  
Дата: 26.01.19 08:42
Оценка:
Здравствуйте, YuriV, Вы писали:

YV>vector<bool> это, как раз, пример когда специализация сужает область применения обобщённой сущности, что есть нонсенс, а значит ошибка архитектуры. Если к специализации нужно писать отдельную рекомендацию по применению, то от такой специализации нужно отказаться. Как здесь правильно сказали следует использовать отдельный тип.


По поводу vector<bool> уже сломано немало копий и мне не хотелось бы в этом топике возобновлять эту дискуссию. Главное, что я хотел выразить здесь: http://rsdn.org/forum/cpp/7353947.1
Автор: rg45
Дата: 21.01.19
, это то, что операции разыменовывания итераторов всех (почти) стандартных контейнеров являются lvalue выражениями, а значит и переменная range for цикла, как бы она ни была объявлена, никак не может быть rvalue ссылкой. А vector<bool> в этом случае — то самое исключение, которое лишь подтверждает общее правило.
--
Отредактировано 26.01.2019 13:45 rg45 . Предыдущая версия . Еще …
Отредактировано 26.01.2019 13:44 rg45 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.