ПрограммированиеФорумОбщее

С++ передача встроенных типов данных по ссылке или по значению? (3 стр)

Страницы: 1 2 3
#30
13:44, 1 июня 2018

me
> Оффтоп.
> Все наверное знают шуточное "прострелить себе ногу" в разных языках
> программирования, а что про Ü можно сказать?
В Ü можно заиспользовать unsafe и отстрелить себе ногу по пояс.

#31
14:18, 1 июня 2018

Panzerschrek[CN]
> > Оффтоп.
> > Все наверное знают шуточное "прострелить себе ногу" в разных языках
> > программирования, а что про Ü можно сказать?
> В Ü можно заиспользовать unsafe и отстрелить себе ногу по пояс.

+ Показать
#32
14:44, 1 июня 2018

Zab
> Так что, можно попасть на дополнительные расходы от косвенности.
нельзя здесь никак попасть. не нужно мусолить xy проблему.
не нужно заморачить себе голову трудностями компилятора.

#33
15:20, 1 июня 2018

Aroch
> встречный вопрос, можно хотя бы жопошный пример когда передача int по значению
> вместо const int& приводила к багам?
Разница между sum и sum_noref - замена T const& на T привела к созданию лишних объектов.

Aroch
> > Это ты так думаешь, а в реальности без явных барьеров оптимизатор и процессор
> > имеют полное право наплевать на твой пул и перемешать чтения/записи так, как им
> > покажется удобнее; вплоть до полного удаления твоего пула из программы.
> Давай пример.
Тело функции bar - компилятор послал все твои пулы к херам и превратил bar в return a.a += 2;

А теперь давай пример из реальной программы.

#34
20:00, 1 июня 2018

Delfigamer
> Разница между sum и sum_noref - замена T const& на T привела к созданию лишних
> объектов.
не увидел ответа на вопрос. Давай две функции с одинаковыми телами, в одном const int& в другой int, от второй жду бага.
> Тело функции bar - компилятор послал все твои пулы к херам и превратил bar в
> return a.a += 2;
опять же полная херня, а что он должен был вернуть?
> А теперь давай пример из реальной программы.
https://ideone.com/ohXjMy

#35
21:44, 1 июня 2018

Aroch
> не увидел ответа на вопрос. Давай две функции с одинаковыми телами, в одном
> const int& в другой int, от второй жду бага.
Читай внимательно - две функции с одинаковыми телами, в одной const T&, во второй - T, вторая коптит.
Или, по-твоему, избыточные аллокации - это не баг?
Или, по-твоему, на каждый шаблон нужно отдельно писать 100500 специализаций на всякие сочетания int, long, double, long double, T*, bool, std::array<float, 2> и ещё целую помойку скалярных типов?

Aroch
> опять же полная херня, а что он должен был вернуть?
Наплевать, что он должен был вернуть. Прочитай свой собственный вопрос ещё раз, читай внимательно:
> > Это ты так думаешь, а в реальности без явных барьеров оптимизатор и процессор
> > имеют полное право наплевать на твой пул и перемешать чтения/записи так, как им
> > покажется удобнее; вплоть до полного удаления твоего пула из программы.
> Давай пример.
temp удалён? Удалён. Пример показан.

Aroch
> > А теперь давай пример из реальной программы.
> https://ideone.com/ohXjMy
Читай внимательно раз:
> пример из реальной программы
Что делает эта программа? Нихрена она не делает, это ещё один жопошный пример.
Читай внимательно два:
Delfigamer
> Это называется "data race" и к данному треду эта проблема никак не относится,
> ни по причинам возникновения, ни по методам решения.
И к тому же твой пример - говно даже как пример:

thread_function_value, x = 9
thread_function_ref, x = 9
thread_function_non_const, x = 10
In Main Thread : Before Thread Start x = 10
In Main Thread : After Thread Joins x = 10

#36
22:30, 1 июня 2018

Delfigamer
> Или, по-твоему, избыточные аллокации - это не баг?
Аллокация чего, pod типа в 4/8 байт? Не баг.
> temp удалён? Удалён. Пример показан.
то есть ты так и не понял в чем поинт 1pool - 1thread? /_-
> И к тому же твой пример - говно даже как пример:
/_-

#37
0:31, 2 июня 2018

Aroch
> /_-
А теперь открой глаза и посмотри на тред:
Panzerschrek[CN]
> Принимать значение - более безопасный (для крестов) способ. Когда передаёшь
> несколько аргументов по ссылке, есть шанс запороть одни аргументы, вычисляя
> другие.
Здесь нет никаких упоминаний о data race. Здесь речь идёт о reference aliasing и о том, что вызов мутирующих методов ломает программу с алиасингом.
Я попросил привести пример реального, применяемого на практике кода, где возникает такая проблема и это не является результатом ошибок при проектировании интерфейсов.
Ты мне в ответ тычешь многопоточными жопопримерами.

Aroch
> Аллокация чего, pod типа в 4/8 байт?
Нет, аллокация std::string с последующим memcpy, потому что код шаблона один и тот же и для скаляров, и для нетривиальных жиртрестов.
Я уже предчувствую, как ты всё забыл, поэтому сразу напомню. Ты сказал:
> если размер 4/8 байта и не предполагается менять значение, то только по значению.
Мой аргумент заключается в том, что если один код работает и со скалярами, и с нетривиалами - то лучше применить const&, в том числе и на размерах 4/8 байт.

#38
1:08, 2 июня 2018

Delfigamer
> Нет, аллокация std::string с последующим memcpy, потому что код шаблона один и
> тот же и для скаляров, и для нетривиальных жиртрестов.

А теперь открой глаза и посмотри на тред:

+ Показать

Чел, судя по твоему тону у тебя уже явно подгорает в одном месте. Почему ты решил что многопоточка идет лесом? Зачем ты вообще тогда полез спорить на тему отдельного пула под поток?

#39
3:40, 3 июня 2018

(1)
Изначальная проблема выглядела так:

Какой вариант предпочтительней для встроенных типов данных float, double
Такой
> шаблон
Или такой
> шаблон
Или компилятор сам поймет как ему оптимизировать и поэтому оставить первый вариант

На что я на первой же странице подробно ответил:

Функции скалярных аргументов заинлайнились до упора - никаких процессов передачи там вообще не остаётся, оптимизатор идёт по значениям напрямую.

Вопрос отвечен, тема закрыта.
_

(2)
Дальше, поднимается другая проблема:

Когда передаёшь несколько аргументов по ссылке, есть шанс запороть одни аргументы, вычисляя другие.

Я ввожу тезис, который позже пересказываю этими словами:

Суть в том, чтобы не менять состояние программы больше одного раза на протяжении одного стейтмента. Как за этим следить - давать методам говорящие названия, по которым можно сразу и однозначно определить - является ли он процедурой или чистой функцией.
Ну и не совать ссылки туда, где должны быть значения.
Если это всякие int/float/void* и прочие скаляры - не нагружать мозг ненужной белибердой и писать согласно семантике - ссылки на месте ссылок, значения на месте значений; потому что в конечном счёте оптимизатор всё равно <...> сделает так, как посчитает нужным.

Мне дают контраргумент:

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

На что я попросил цитату из реального кода, где возникшую проблему "запороть одни аргументы, вычисляя другие" нельзя было бы избежать только соблюдением правил гигиены.
Приведённые здесь примеры не подходят, потому что, очевидно, нарушают эти правила ради выразительности примера.
Никаких цитат в ответ не поступило, так что этот вопрос всё ещё остаётся открытым.
_

(3)
Тем временем, появляется заявление:

если размер 4/8 байта и не предполагается менять значение, то только по значению

На которое... я не обратил внимания. Вообще. Речь шла только о наложение ссылок (тезис 2) и многопоточности (тезис 4). Тем не менее, поступил запрос:

встречный вопрос, можно хотя бы жопошный пример когда передача int по значению вместо const int& приводила к багам?

которое я воспринял как просьбу привести пример, где передача скаляра по ссылке предпочтительнее, чем по значению. Соответственно, в ответе я привёл шаблонный код, который работает одновременно и с int, и с std::string. Поскольку он работает с std::string, то передача значений через T const& вместо T объективно лучше, поскольку не создаёт лишние копии строк. А поскольку разница между int const& и int в этом контексте несущественна* - проще оставить ссылку на все варианты T, чем отдельно специализировать шаблон для скаляров. Конкретно в этой ситуации, передача чисел через T const& предпочтительнее, чем через T - иначе, либо потратятся ресурсы рантайма на создание копий строк, либо потратятся ресурсы разработчика на написание специализаций.
А что, если точно известно, что шаблон никогда не будет использоваться с нескалярными T? Тогда никакой разницы*, конечно же, пусть делает как хочет.
* Считая, что программист соблюдает правила гигиены и тезис (2) остаётся неопроверженным.
_

(4)
И совершенно само по себе, в примере #23 было высказано утверждение:

// or changed in another thread

Которое я воспринял как «так же, запись значения во временную переменную простым присваиванием защищает от data race» - что является грубой ошибкой, о чём я и сказал:

Это называется "data race" и к данному треду эта проблема никак не относится, ни по причинам возникновения, ни по методам решения.
В реальности без явных барьеров оптимизатор и процессор имеют полное право наплевать на твой пул и перемешать чтения/записи так, как им покажется удобнее; вплоть до полного удаления твоего пула из программы.

Дальше, в ответ на запрос, я привёл реальный пример описанной оптимизации #33, а потом - предоставил ссылку на объяснение, почему подобное поведение является, фактически, undefined behavior.
В ответ поступил контрпример #34, однако, этот контрпример обладает рядом недостатков:
1. Он описывает иную ситуацию - тогда как в оригинальном коде происходит простое присваивание, в контрпримере вместо него происходит передача значений через конструктор std::thread - что, в отличие от присваивания, является явной точкой синхронизации. Следовательно, этот пример неудачен как опровержение тезиса 4, поскольку не противоречит ему.
2. Он не соответствует запросу - контрпример #34 имеет целью опровергнуть тезис 4, однако, в сообщении он был предоставлен как аргумент против тезиса 2. Разумеется, с проблемой в тезисе 2 - «Когда передаёшь несколько аргументов по ссылке, есть шанс запороть одни аргументы, вычисляя другие» - контрпример #34 не имеет ничего общего.
3. Самоописание примера противоречит его собственной семантике - одно из чтений обозначено как "значение перед запуском потоков", но при этом расположено после вызова конструкторов std::thread и, таким образом, образует data race и приводит к неопределённому поведению.
Из этих недостатков я сделал вывод, что человек, привёдший контрпример #34, обладает ограниченными и, в определённых местах, ошибочными знаниями в области многопоточного программирования.

#40
4:43, 3 июня 2018

Delfigamer
бла бла, а по сути, константная ссылка подразумевает что объект не будет модифицироваться с момента входа в функцию и до ее завершения. Пользователь глядя на объявление функции foo(const& ...) наивно полагает что так оно и будет. Только узнать это наверняка можно заглянув в реализацию функции, иначе всегда есть шанс прострелить колено ибо кресты. Но самое смешное что если функция плюет на const и меняет внутри себя косвенно или явно значение, то для тебя это не баг и всё путем. А если у нас "лишние" создание pod типа на 4/8 байт, то это баг /_-
И еще приведи реальные примеры из каких-нибудь более менее адекватных библиотек где в объявлениях функций встречалось const float&, const int& etc, без шаблонодерьма, мне что-то ни разу такие не попадались.

#41
5:00, 3 июня 2018

Aroch
> бла бла, а по сути, константная ссылка подразумевает что объект не будет
> модифицироваться с момента входа в функцию и до ее завершения. Пользователь
> глядя на объявление функции foo(const& ...) наивно полагает что так оно и
> будет. Только узнать это наверняка можно заглянув в реализацию функции, иначе
> всегда есть шанс прострелить колено ибо кресты.
Delfigamer
> (2)
> Я ввожу тезис, который позже пересказываю этими словами:
> Суть в том, чтобы не менять состояние программы больше одного раза на
> протяжении одного стейтмента. Как за этим следить - давать методам говорящие
> названия, по которым можно сразу и однозначно определить - является ли он
> процедурой или чистой функцией.
> Ну и не совать ссылки туда, где должны быть значения.
> Если это всякие int/float/void* и прочие скаляры - не нагружать мозг ненужной
> белибердой и писать согласно семантике - ссылки на месте ссылок, значения на
> месте значений; потому что в конечном счёте оптимизатор всё равно <...> сделает
> так, как посчитает нужным.

Aroch
> Но самое смешное что если функция плюет на const и меняет внутри себя косвенно
> или явно значение, то для тебя это не баг и всё путем. А если у нас "лишние"
> создание pod типа на 4/8 байт, то это баг /_-
Delfigamer
> Речь шла только о наложение ссылок (тезис 2) и многопоточности (тезис 4). Тем
> не менее, поступил запрос:
> > встречный вопрос, можно хотя бы жопошный пример когда передача int по значению
> > вместо const int& приводила к багам?
> которое я воспринял как просьбу привести пример, где передача скаляра по ссылке
> предпочтительнее, чем по значению. Соответственно, в ответе я привёл шаблонный
> код
Delfigamer
> А что, если точно известно, что шаблон никогда не будет использоваться с
> нескалярными T? Тогда никакой разницы*, конечно же, пусть делает как хочет.

Aroch
> И еще приведи реальные примеры из каких-нибудь более менее адекватных библиотек
> где в объявлениях функций встречалось const float&, const int& etc, без
> шаблонодерьма, мне что-то ни разу такие не попадались.
Delfigamer
> А что, если точно известно, что шаблон никогда не будет использоваться с
> нескалярными T? Тогда никакой разницы*, конечно же, пусть делает как хочет.

#42
5:00, 3 июня 2018

Delfigamer
> я попросил цитату из реального кода, где возникшую проблему "запороть одни
> аргументы, вычисляя другие" нельзя было бы избежать только соблюдением правил
> гигиены.
> Приведённые здесь примеры не подходят, потому что, очевидно, нарушают эти
> правила ради выразительности примера.
> Никаких цитат в ответ не поступило, так что этот вопрос всё ещё остаётся
> открытым.

#43
14:24, 3 июня 2018

Delfigamer
> нельзя было бы избежать только соблюдением правил
> > гигиены.
передача по значению как раз и есть часть этой гигиены, до тебя это всё никак не дойдет почему то. В тех случаях когда подобная "прививка" не будет ничего стоить грех ею не пользоваться. И у тс'а как раз такой случай.

Страницы: 1 2 3
ПрограммированиеФорумОбщее

Тема в архиве.