Вернёмся к примеру с двумерным массивом a[2][4]. Результатом первого оператора индексирования a[0] будет указатель на int[4], а значит доступ может осуществляться только в интервале [0...3].
Я понимаю, что массивы — это массовая слабая область знаний у очень многих. Но коль пишется статья, почему бы не вычистить её от таких ошибок, дав на вычитку искушённым людям, дабы не распространять заблуждения?
Результатом первого оператора индексирования a[0] будет отнюдь не указатель на int[4].
И далее здесь в комментариях есть даже ссылка на ответ ИИ по этому поводу.
Вот мне кажется, что текущие компиляторы для х86/х64 кинут литерал в сегмент данных и ссылка никогда не пропадёт.
В данном случае вам кажется совершенно правильно.
Но это стандартом для всех систем и оптимизаторов! не гарантируется.
Почему вы не проверили это своё утверждение и не предупредили, что, вполне возможно, это вам только кажется?
Тем более, что сейчас достаточно задать ИИ всего два вопроса:
Каково время жизни строкового литерала в программе на языке C++?
и
В каком пункте стандарта C++17 говорится об этом?
чтобы получить исчерпывающий ответ (я здесь использовал Gemini, он у меня — "дежурный" ИИ) и просто открыть указанные ИИ 2 пункта стандарта с cppreference.
Первый (по ссылке нужный фрагмент подсвечен светло-зелёным):
16 Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified. [ Note: The effect of attempting to modify a string literal is undefined. — end note ]
1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program ([basic.start.static], [basic.start.term]).
Локальная переменная, это fst в шаблоне bind_first(FST &&... fst) , которая захватывается в лямбду (в предыдущем комментарии я опечатался про корутину).
А какого типа эта переменная?
И да, в вашем примере (если бы он был рабочим), это была бы строковая переменная.
Что значит, строковая переменная? Какой у неё тип?
Я — к тому, что в данном конкретном случае:
auto const sendOrderGoog{bind_first<SendOrder>("Goog")};
dangling reference не образуется, и последующее использование sendOrderGoog в примере безопасно.
Но в общем случае, проблема, естественно, имеется.
Но в данном случае при показанном конкретном примере использования dangling reference не образуется.
Я, на самом деле, когда писал, сначала задумался, что туда вписать, решил сначала временно вписать туда &, сделать основное, а потом вернуться к вопросу.
А именно так ведь на практике всё и происходит. Ваш коллега написал какой-то код, вы через полгода его меняете. Вы не то что «забыли здесь то», вы этого и не помнили никогда. Или вы ожидаете, что каждый контрибьютор в кодовую базу будет следить за всеми изменениями и поддерживать ментальный контекст каждого другого контрибьютора? Или даже если вы сами написали — через полгода вы уже забудете такие нелокальные финты.
Тогда для такой практики в коде нужны комментарии, составленные исходя из обозначенной проблемы.
Или времени и на это нет, и поэтому лучше отказываться от перегрузки функций?
ключ не в планировании на года вперёд, а в написании кода так, чтобы при его изменении компилятор вас тыкнул носом в максимальное количество мест, где ломаются предположения из-за ваших свежих изменений.
Это тогда потребуется писать каким-нибудь особо специальным образом, и не всегда удастся придумать решение для этого.
А обсуждаемый подход её только усиливает.
Если не думать и не хотеть решить проблему, сохранив решение, то так оно и останется.
Вот мне же почему-то удаётся находить решения, несмотря на то, что я, года два, если не три, как подзабросил C++, и только сейчас постепенно возвращаюсь к нему.
Удаётся, потому что хочу решить проблему и пытаюсь думать в нужном направлении.
Какой бы вы предложили?
Конкретный не предложу, но — очевидно, что в языке не должно быть UB. Уже только одно это — огромный шаг вперёд.
Или, наоборот, предварительная проверка — это лишние сотни наносекунд, и вы проиграли тем, кто их не делает (а выражает все требования в типах и проверяет максимальное их число при компиляции, например).
В обсуждаемом случае речь была явно не про HFT.
Мы можем усложнять этот пример бесконечно, но смысл, опять же, я надеюсь, понятен: полагаться на внешние ограничения — не всегда возможно, либо не всегда остановит вас достаточно рано.
Я говорил о том, что авторы статьи не потрудились выдумку свою соотнести с реальностью.
Нельзя отправить ордер с такого объёма с тем, чтобы он успешно исполнился, поэтому и обанкротиться таким образом нельзя.
С каким — таким? «Посмотреть предложенный собеседником код и найти там проблемы»?
Нет, с подходом "забуду здесь то", "забуду там это".
Проблемы с предложенным вами подходом потому, что он нелокален. Ну, вернее, это проблема не вашего подхода, а общей философии C++: например, если вы почитаете или послушаете гугловского Титуса Винтерса, топящего за что-то вроде «C++ design unit is an overload set» (а не функция или класс или модуль или…), и послушаете про его же кулстори про эволюцию гугловской кодовой базы, то увидите, что добрая часть проблем вылезает именно из-за этой нелокальности. Семантика, скрывающаяся за именем, оказывается размазана не по одному определению одной функции за этим именем, а по всему множеству всех функций с этим именем, потенциально в разных неймспейсах
Да, проблема имеется, но это лишь значит, что следует стараться её обходить и избегать.
Моей заботой (и вообще обязанностью) как программиста инфры было именно обеспечить максимально комфортную жизнь трейдерам, которые в статистике и прочих своих этих всех альфах-бетах разбираются куда лучше, чем в C++.
Трейдерам следует программировать на C++ только в одном случае: если они, в первую очередь, программисты на C++, а трейдеры они — уже по совместительству.
В остальных случаях это похоже на попытку бриться топором. Одна ошибка — и весьма серьёзные последствия не заставят себя ждать.
У трейдеров должен быть другой язык программирования.
Речь о другом: у предложенного механизма есть много негативных аспектов, поэтому говорить, что он эквивалентен решениям из раста (или из хаскеля — я так-то раст не люблю и хаскелист вообще), несколько нечестно.
Я и не говорил, что он эквивалентен.
Я говорил, что он в C++ — есть, а в статье неявно подразумевается, что — нет.
Как успехи с продумыванием кодовой базы на года вперёд?
Это — не панацея, но если этим не заниматься, будет значительно хуже.
Ну, да. Но в этом случае она вылезает тоже.
Если не думать, то проблему не решить в 100% случаев. Если же думать, то процент начинает ощутимо отличаться от 100.
Я решил проблему, связанную с тем, что функции `sendOrder` — перегруженные, и поэтому механизм std::bind_first не работает.
Удалось отложить инстанцирование и, соответственно, разрешение перегрузки, которая теперь происходит не в момент вызова bind_first, а в момент вызова того, что вернула bind_first (добавился шаблон класса SendOrder и шаблон функции bind_first, и этот шаблон в качестве первого параметра принимает шаблон класса, а не тип или значение):
При вызове bind_first необходимо явно указывать первый параметр шаблона.
Класс SendOrder — один на все перегрузки sendOrder.
Я не знаю ни одного человека, решившего задачу останова, и не знаю ни одного человека, который бы знал C++.
Эти данные — слишком скудные, чтобы делать выводы по данному вопросу.
Knight capital — это так, намёк на то, что при факапах в коде проверки и ограничители срабатывают не сразу, и даже их может оказаться недостаточно (они ж обанкротились и закрылись).
Так там не в ограничениях дело было. Он же не пытались купить или продать сразу 2^32 акций.
Так в коде выше на биржу уходит тоже большое число относительно мелких (если хочется, можете вместо sendOrder читать splitAndExecuteOrder или чё-т такое, сути это не меняет).
Если оно уходит без предварительной проверки достаточности средств, то это — вопиющая некомпетентность брокера, потому что шортятся акции под залог, и следует проверить его размер, иначе у брокера будут проблемы, если с трейдера нечего взять, а цена резко улетит вверх.
И мне почему-то кажется, что долго такой брокер не "проживёт".
Тем более, что если купить без плеча на N денег акций, то потерять, в худшем случае, можно не более N денег.
А зашортив акций на N денег, потерять можно неограниченное количество денег. Например, если после шорта акция выросла в 15 раз в цене, потери составят 15 * N денег.
И реальные случаи такие уже были.
Или вы думаете, что если вам надо купить/продать 100500 акций, то вы их покупаете одним пакетом? Это плохая идея по куче причин.
Критикуя статью, в частности, банкротство при отправке на продажу 2^32 акций, я подробно описывал детали продажи такого количества акций, откуда должно быть понятно, что в базовых вещах, связанных с биржевой торговлей, я разбираюсь весьма неплохо.
Ожидать, что люди будут в продакшене писать и поддерживать такой код — несерьёзно.
Дело в том, что это — код, демонстрирующий идею и её работоспособность, а не код для production'а.
Не знаю, почему вы восприняли его как код для production'а.
Если что-то применимо к функции, то логично предположить, что это применимо и к методам, и к шаблонам функций/методов, а в некоторых случаях — и к лямбдам.
Это не всегда так, потому что могут быть препятствующие тому причины, но по "философии" C++ логично это предположить.
Никто не знает С++ (с)
Это — верно, но "философия" C++, а также внутреннее ощущение от свойств механизмов C++ часто выручает.
Именно внутренне ощущение от механизма = delete натолкнуло меня на мысль о применении его здесь.
Вот я скопипастил ваш код (и заодно добавил requires из соседнего поинта) и сделал вид, что он эволюционирует со временем, «забыв» поменять тип первого аргумента в удалённой перегрузке:
С таким подходом проблемы будут независимо от языка.
Сможете объяснить среднему трейдеру, который на C++ пишет постольку, поскольку вы ему даёте апишку для вашего инфра-кода, а у себя он там обмазывается q, матлабами и прочим?
Наверное, это не его забота, обеспечить приёмистость не точно соответствующих типов в предоставляемом API, — но только таких, которые разрешены проектировщиком API, а не любых, которые язык позволяет.
Есть предложенный механизм, и если хотеть добиться результата, этот механизм можно использовать для достижения этого самого результата.
Сможете быть уверенным, что сможете адекватно поддерживать кодовую базу на миллион-другой строк, где подобными финтами всё обмазано, и где простейшее изменение рискует превратиться в сутки-другие расхлёбывания выблева компилятора минимум, и где рекомпиляция одного TU занимает минуты даже в дебаг-билде, без оптимизаций?
Если не продумывать каждое решение, а пытаться наворачивать сверху, да побыстрее, а также быть вынужденным постоянно что-то менять, — да проблемы будут.
Да, а что? std::bind_front(&sendOrder, "GOOG");
Эта проблема не является специфичной для данного случая. Придётся приводить к одной из перегрузок тем или иным способом или указывать явно параметр шаблона.
И если хочется, чтобы это работало, как будто перегрузка теперь действует для тех же функций, но без первого параметра, который теперь фиксирован, и который не требуется передавать, придётся думать, как создать такое решение.
Почему? Я хочу, чтобы у меня в кэшлайн помещалось 16 цен, а не 8 — почему вы мне запрещаете так делать?
Я не запрещаю, это — просто наблюдение.
Не, просто задача «освоить C++» примерно настолько же реализуема, как «решить проблему останова».
Всё же, первая задача значительно проще, вы преувеличиваете. Правда, это не значит, что первую задачу можно досконально решить. Но досконально и не требуется.
Вовсе нет. Просто считать, что это число вот прям сразу пойдёт в пакетик на биржу — это несколько ошибочно.
Это, по всей видимости, не имеет отношения к реально происходившим событиям, потому что сделка была не одна большая, а — большое количество относительно мелких.
И если вы хотите купить 10 акций, а случайно покупаете -10 = 4294967286, то до того, как у вас сработают всякие риск-чеки, дневные лимиты, и прочее, у вас уже уйдёт ордеров на сотню тыщ акций.
Нет, сработает проверка на максимальный объём в одной сделке, и вернётся ошибка, ничего никуда не уйдёт.
И если бы ушло, то ордер был бы один.
Ещё код по теме можно посмотреть в моём ответе @boldapeу здесь.
Начну с конца, кгайт капитал это не догадка о том откуда вы узнали про бизнес логику биржевых торгов, а ключевая фраза для самостоятельного гугления эпического эпик фэйла на плюсах, как раз из области трэйдинга.
А вы сами — в курсе, что там произошло, и при чём здесь, вообще, C++?
И в наше время Google'ить такие вещи — неэффективно, особенно, если необходимо понять суть, а не поверить в чей-то пересказ через 10-ые руки.
Отсылка к учебному примеру означает что в реальном коде будет очень много отвлекающих ньюансов которые со 100% вас успешно отвлекут от сути проблемы, поэтому нельзя винить человека в незнании чего то лишь потому что вы с лёгкостью обошли проблему учебного примера.
Учебный он или нет — не важно. Имеющуюся проблему не пытались решить по-настоящему. Для этого не требуется знать C++ досконально. И это — не какая-то редко используемая тонкость редко используемого механизма.
Отсылка к проблеме остонова означает оценку сложности такой "простой" задачи как "пойди уже и выучи наконец плюсы" как равную == задача невыполнима в принципе.
Это — несопоставимые по сложности задачи, C++ выучить значительно проще, тем более, что для решения данной задачи не требуется его учить досконально.
В пункте про дабл или флот, ударение стоит на ИЛИ. Я не уверен конечно, но подозреваю что сейчас вероятно передать флоат там где у вас сигнатура ожидает дабл не удастся, хотя выглядит безопасно, разумно и удобно, но я не проверял. В любом случае если ваша сигнатура требует принимать несколько типов в ТОМ же самом параметре, которые из коробки могут друг в друга преобразовываться, то придется обмазываться концептами.
Пункт про обновление сигнатуры это когда вы решили добавить ещё один параметр и сделали это только в реальной функции, но забыли (или если джун, то даже и не предполагали что надо) обновить темплэйт делет, чтобы учесть новый параметр.
По поводу добавления параметров как для единственной функции, так и для перегруженных функций: можно применить parameter pack в шаблоне.
Один шаблон с parameter pack'ом, который "запрещает приведения".
Затем ещё один перегруженный шаблон с использованием SFINAE выступает обёрткой, но только для тех вызовов, в которых используется хотя бы один float.
Перегрузок много, а шаблон функции-обёртки — один.
Наверное, можно ещё что-нибудь придумать на эту тему, но для этого необходимо забыть про Rust, и начать хотеть найти решение, а не искать оправдания, почему решение искать не сто́ит.
Потому что вам теперь надо обновлять обе сигнатуры, и компилятор далеко не всегда напомнит вам это сделать.
Зачем их обновлять?
Если добавляются перегрузки с другим числом параметров, — да, ещё шаблоны придётся добавлять.
Потому что теперь вы не можете взять адрес sendOrder(по крайней мере, в контекстах вроде аргумента для стандартных алгоритмов, где ожидаемый тип callable не фиксирован).
Если имеются перегрузки, это и так невозможно без фиксации ожидаемого типа. И это — правда, та функция, адрес которой, весьма вероятно, необходимо будет брать?
Потому что если вы захотите принимать doubleилиfloatпоследним аргументом
Сейчас там и так double последним аргументом. В таких местах float не используется.
И решить проблему останова на сдачу.
В данной задаче это — необходимо? По-моему, вы выдумываете несуществующие трудности.
Человек, отвечающий подробное, даже не понимает смысла учебных, иллюстрирующих примеров.
Но сначала он обращает внимание на количество (quantity) и стоимость (price), подчеркнув, что C++ сильно усложняет защиту вызывающей стороны от ошибок: компилятор допускает и 1000.00 в качестве quantity, и 100 в качестве price, не выдавая никаких предупреждений, несмотря на то, что они относятся к другим типам. Он просто выполняет преобразования.
Наверное, прежде чем "продавать" что-то сомнительное, следовало бы научиться пользоваться C++:
При попытке раскомментировать за'if'-0-енное, компилятор отказывается компилировать.
Почему не было даже попыток применить данное решение?
В результате вы продадите 4294967196 акций и обанкротитесь.
Человек, утверждающий подобное, даже не пытался изучить предмет.
Не каждый эмитент имеет столько выпущенных акций.
Хорошо, пусть речь идёт о таком эмитенте, который выпустил столько или большее количество акций.
Очевидно, что обычный трейдер не обладает таким количеством акций, и чтобы их продать, их необходимо зашортить, то есть, сначала занять у брокера.
Вряд ли у брокера есть столько акций, но даже если есть, он не выдаст акции взаймы просто так, а — только под залог депозита или его части.
У подавляющего большинства трейдеров нет столько денег на депозите.
Хорошо, предположим, что и деньги есть, и у брокера есть необходимое количество акций.
Чтобы их продать, необходимо, чтобы их кто-то сразу купил, а для этого в биржевом "стакане" должны быть заранее выставлены лимитные заявки на покупку всего объёма продаваемых акций.
Очевидно, что это — весьма маловероятное событие.
Наконец, как правило у брокера в API есть ограничение на объём в одной торговой операции, которое значительно меньше 4294967196.
Но — зачем все эти тонкости, если можно просто ляпнуть о банкротстве?
Вместо всего этого, насколько я понимаю, была ссылка на авторитет.
Однако, авторитетов не существует, и каждый раз необходимо обосновывать, а не ссылаться на свой или чужой авторитет, что это кто-то авторитетный сказал, потому что каким бы ни был авторитетным человек, он может ошибиться.
Бесполезно продавать Rust, тем более, таким способом.
5-10 лет практики программирования имеет человек на выходе из универа, и его можно условно считать джуном (т.е. человеком который более менее усвоил теор. минимум https://sharpc.livejournal.com/67583.html).
Зачем требовать от джуна-программиста требования знания электроники, тем более, аналоговой, которая на порядки сложнее в понимании, чем цифровая?
Ладно электроники, зачем от него требовать знания автомата Калашникова?
Может, ещё потребовать теоретические знания, связанные с артиллерией, включая детали, связанные с физикой выстрела и полёта снаряда, и заканчивая знаниями особенностей современных видов пороха и прочих взрывчатых веществ как с точки зрения химии, так и с точки зрения физики?
Есть такие люди, которые заявляют на много порядков бо́льшие требования, чем они есть на самом деле, и делают вид, что это и есть истинное положение вещей.
Сеньор-программист, наверное, тогда должен знать всю геологию, всю космическую область, включая особенности, связанные с релятивистскими эффектами, а также атомные технологии, применяющиеся как в атомной промышленности, так и в военной сфере. Бонусом будет знание теоретической физики и физики ядерных частиц. Да?
Более того, в стандарте сказано, что rand выдаёт значения от 0 до RAND_MAX. С чего вы взяли, что на платформе автора RAND_MAX не больше чем в три раза меньше INT_MAX?
Опять же, я — об общем случае, а не обо всех случаях.
Это уже казуистика пошла, но если так хотите: вы не показали, что в этом коде возникает переполнение инта.
Я не показал, что переполнение int'а возникает для любых случаев, зато показал, что возникает для одного конкретного.
Очевидно, что этот конкретный случай — не единственный, есть ещё и другие случаи, для которых возникает переполнение.
Во-первых стандарт не гарантирует случайность функции rand
Опять же, вы опровергаете не то, о чём я говорил. Я не говорил, что проблема наличествует для всех случаев.
во-вторых автор мог заранее проверить, что при конкретном сиде не возникает переполнение
Ну, и что, что в каких-то конкретных случаях проблемы нет?
В общем-то случае проблема имеется.
Более того, некоторые LLM-ки это "видят" и даже пытаются "думать" в правильном направлении, хотя и с ошибками.
В частности по второй ссылке, которую привёл @izuck3n можно по строке "Integer overflow risk" обнаружить следующее:
Summing three rand() calls can overflow the range of int on platforms where RAND_MAX is near INT_MAX. Unsigned would wrap, signed is undefined behavior. A safer approach if you really want to combine calls is to do something like
unsigned long sum = (unsigned)rand() + (unsigned)rand() + (unsigned)rand();
RANDOM = sum / 3;
Предложение от ChatGPT — неверное, но "ход мысли", в целом, верный.
Так что проблема не только имеется, но она ещё и не остаётся незамеченной некоторыми моделями.
И проблема будет проявляться в очень существенном количестве случаев, навскидку — в половине случаев, поэтому "не заметить" её будет нельзя.
Иногда проще получить ответ brute-force'ом, что я и сделал.
Можно не дёргать каждый раз srand, а выполнить его один раз вначале или вообще не выполнять ни разу, — результат получается одинаковый.
Как видно, UB имеется в 83% случаев. Игнорировать такой процент случаев — невозможно.
Ой ну какой вы прямо, ну дайте же мне похвастаться :)
Так вы и похвастались.
Смысл в том, что 45-летняя тётка с советским бэкграундом отважилась влезть в инвестирование, и все получилось.
Если купить индекс на много лет, то как тут может не получиться, даже если купить прямо перед кризисом?
Просто менее эффективно, чем могло бы быть, если купить сразу после кризиса.
Так что дочери автора, современной молодой девушке, сам бог велел!
А вы знаете, какой силы потрясение ожидает рынки в ближайшие месяц-два-три?
Инвестировать следует аккурат сразу после кризиса, а не до. Иначе — неэффективно получается: несколько лет ждать придётся, пока последующий рост перекроет падение в кризис. И только потом пойдёт доход.
Посмотрите курс SP500 в 2008-ом году и в 2009-ом. Ориентировочно, 1400 и 870. И вернулся к 1400 только к 2012-ому году.
Если его купить в 2008-ом по 1400, то в 0 выйти удастся только к 2012-ому. 4 года ожидания выхода из убытков, и только потом начинает идти прибыль.
А если купить на год позже, в 2009-ом, по 870, то через 3 года, к 2012-ому, прибыль составит 61%. Ведь есть же разница?
То есть, лучше год подождать, пока всё упадет до дна, и тогда и инвестировать.
Правда, нынешний кризис — не такой, как предыдущие, неизвестно, когда рост начнётся. Не один год может пройти, и не два. Да и рынки могут кардинально поменяться.
Поэтому я сомневаюсь, что кто-то там велел сейчас инвестировать.
Нет, в статье до сих пор написано:
Я понимаю, что массивы — это массовая слабая область знаний у очень многих.
Но коль пишется статья, почему бы не вычистить её от таких ошибок, дав на вычитку искушённым людям, дабы не распространять заблуждения?
Результатом первого оператора индексирования
a[0]
будет отнюдь не указатель наint[4]
.И далее здесь в комментариях есть даже ссылка на ответ ИИ по этому поводу.
В данном случае вам кажется совершенно правильно.
Почему вы не проверили это своё утверждение и не предупредили, что, вполне возможно, это вам только кажется?
Тем более, что сейчас достаточно задать ИИ всего два вопроса:
и
чтобы получить исчерпывающий ответ (я здесь использовал Gemini, он у меня — "дежурный" ИИ) и просто открыть указанные ИИ 2 пункта стандарта с cppreference.
Первый (по ссылке нужный фрагмент подсвечен светло-зелёным):
и второй:
Как видите, гарантируется.
Верно, следует захватить, применив
std::forward
:Нет, в суть ссылок я вник как следует уже давно.
Здесь просто не продумал этот момент.
А какого типа эта переменная?
Что значит, строковая переменная?
Какой у неё тип?
Я — к тому, что в данном конкретном случае:
dangling reference не образуется, и последующее использование
sendOrderGoog
в примере безопасно.Но в общем случае, проблема, естественно, имеется.
А если "локальная переменная" сама является ссылкой?
Там, на самом деле, не локальная переменная, а параметр функции, который является ссылкой.
Будет ли ссылка на него ссылкой на локальную переменную, находящуюся в этой функции?
Кстати, сомневаюсь, что тупой в состоянии разобраться в C++.
Не удалось подумать, @eao197 уже подсказал.
Но в данном случае при показанном конкретном примере использования dangling reference не образуется.
Я, на самом деле, когда писал, сначала задумался, что туда вписать, решил сначала временно вписать туда
&
, сделать основное, а потом вернуться к вопросу.Основное сделал, а вернуться к вопросу забыл.
Как-то так, в первом приближении, должно выглядеть.
Тогда для такой практики в коде нужны комментарии, составленные исходя из обозначенной проблемы.
Или времени и на это нет, и поэтому лучше отказываться от перегрузки функций?
Это тогда потребуется писать каким-нибудь особо специальным образом, и не всегда удастся придумать решение для этого.
Если не думать и не хотеть решить проблему, сохранив решение, то так оно и останется.
Вот мне же почему-то удаётся находить решения, несмотря на то, что я, года два, если не три, как подзабросил C++, и только сейчас постепенно возвращаюсь к нему.
Удаётся, потому что хочу решить проблему и пытаюсь думать в нужном направлении.
Конкретный не предложу, но — очевидно, что в языке не должно быть UB. Уже только одно это — огромный шаг вперёд.
В обсуждаемом случае речь была явно не про HFT.
Я говорил о том, что авторы статьи не потрудились выдумку свою соотнести с реальностью.
Нельзя отправить ордер с такого объёма с тем, чтобы он успешно исполнился, поэтому и обанкротиться таким образом нельзя.
Нет, с подходом "забуду здесь то", "забуду там это".
Да, проблема имеется, но это лишь значит, что следует стараться её обходить и избегать.
Трейдерам следует программировать на C++ только в одном случае: если они, в первую очередь, программисты на C++, а трейдеры они — уже по совместительству.
В остальных случаях это похоже на попытку бриться топором.
Одна ошибка — и весьма серьёзные последствия не заставят себя ждать.
У трейдеров должен быть другой язык программирования.
Я и не говорил, что он эквивалентен.
Я говорил, что он в C++ — есть, а в статье неявно подразумевается, что — нет.
Это — не панацея, но если этим не заниматься, будет значительно хуже.
Если не думать, то проблему не решить в 100% случаев.
Если же думать, то процент начинает ощутимо отличаться от 100.
Я решил проблему, связанную с тем, что функции `sendOrder` — перегруженные, и поэтому механизм
std::bind_first
не работает.Удалось отложить инстанцирование и, соответственно, разрешение перегрузки, которая теперь происходит не в момент вызова
bind_first
, а в момент вызова того, что вернулаbind_first
(добавился шаблон классаSendOrder
и шаблон функцииbind_first
, и этот шаблон в качестве первого параметра принимает шаблон класса, а не тип или значение):При вызове
bind_first
необходимо явно указывать первый параметр шаблона.Класс
SendOrder
— один на все перегрузкиsendOrder
.Эти данные — слишком скудные, чтобы делать выводы по данному вопросу.
Так там не в ограничениях дело было.
Он же не пытались купить или продать сразу 2^32 акций.
Если оно уходит без предварительной проверки достаточности средств, то это — вопиющая некомпетентность брокера, потому что шортятся акции под залог, и следует проверить его размер, иначе у брокера будут проблемы, если с трейдера нечего взять, а цена резко улетит вверх.
И мне почему-то кажется, что долго такой брокер не "проживёт".
Тем более, что если купить без плеча на N денег акций, то потерять, в худшем случае, можно не более N денег.
А зашортив акций на N денег, потерять можно неограниченное количество денег. Например, если после шорта акция выросла в 15 раз в цене, потери составят 15 * N денег.
И реальные случаи такие уже были.
Критикуя статью, в частности, банкротство при отправке на продажу 2^32 акций, я подробно описывал детали продажи такого количества акций, откуда должно быть понятно, что в базовых вещах, связанных с биржевой торговлей, я разбираюсь весьма неплохо.
Дело в том, что это — код, демонстрирующий идею и её работоспособность, а не код для production'а.
Не знаю, почему вы восприняли его как код для production'а.
Это предполагается по "философии" C++.
Если что-то применимо к функции, то логично предположить, что это применимо и к методам, и к шаблонам функций/методов, а в некоторых случаях — и к лямбдам.
Это не всегда так, потому что могут быть препятствующие тому причины, но по "философии" C++ логично это предположить.
Это — верно, но "философия" C++, а также внутреннее ощущение от свойств механизмов C++ часто выручает.
Именно внутренне ощущение от механизма
= delete
натолкнуло меня на мысль о применении его здесь.С таким подходом проблемы будут независимо от языка.
Наверное, это не его забота, обеспечить приёмистость не точно соответствующих типов в предоставляемом API, — но только таких, которые разрешены проектировщиком API, а не любых, которые язык позволяет.
Есть предложенный механизм, и если хотеть добиться результата, этот механизм можно использовать для достижения этого самого результата.
Если не продумывать каждое решение, а пытаться наворачивать сверху, да побыстрее, а также быть вынужденным постоянно что-то менять, — да проблемы будут.
Эта проблема не является специфичной для данного случая.
Придётся приводить к одной из перегрузок тем или иным способом или указывать явно параметр шаблона.
И если хочется, чтобы это работало, как будто перегрузка теперь действует для тех же функций, но без первого параметра, который теперь фиксирован, и который не требуется передавать, придётся думать, как создать такое решение.
Я не запрещаю, это — просто наблюдение.
Всё же, первая задача значительно проще, вы преувеличиваете.
Правда, это не значит, что первую задачу можно досконально решить.
Но досконально и не требуется.
Это, по всей видимости, не имеет отношения к реально происходившим событиям, потому что сделка была не одна большая, а — большое количество относительно мелких.
Нет, сработает проверка на максимальный объём в одной сделке, и вернётся ошибка, ничего никуда не уйдёт.
И если бы ушло, то ордер был бы один.
Ещё код по теме можно посмотреть в моём ответе @boldapeу здесь.
А вы сами — в курсе, что там произошло, и при чём здесь, вообще, C++?
И в наше время Google'ить такие вещи — неэффективно, особенно, если необходимо понять суть, а не поверить в чей-то пересказ через 10-ые руки.
Учебный он или нет — не важно.
Имеющуюся проблему не пытались решить по-настоящему.
Для этого не требуется знать C++ досконально.
И это — не какая-то редко используемая тонкость редко используемого механизма.
Это — несопоставимые по сложности задачи, C++ выучить значительно проще, тем более, что для решения данной задачи не требуется его учить досконально.
По поводу добавления параметров как для единственной функции, так и для перегруженных функций: можно применить parameter pack в шаблоне.
Примерно, так:
Теперь единственный шаблон "обслуживает" все перегрузки функции
sendOrder
.Его не требуется обновлять.
По поводу
double
илиfloat
: что значит "обмазываться"?Применять?
Можно и применить, например:
Один шаблон с parameter pack'ом, который "запрещает приведения".
Затем ещё один перегруженный шаблон с использованием SFINAE выступает обёрткой, но только для тех вызовов, в которых используется хотя бы один
float
.Перегрузок много, а шаблон функции-обёртки — один.
Наверное, можно ещё что-нибудь придумать на эту тему, но для этого необходимо забыть про Rust, и начать хотеть найти решение, а не искать оправдания, почему решение искать не сто́ит.
Зачем их обновлять?
Если добавляются перегрузки с другим числом параметров, — да, ещё шаблоны придётся добавлять.
Если имеются перегрузки, это и так невозможно без фиксации ожидаемого типа.
И это — правда, та функция, адрес которой, весьма вероятно, необходимо будет брать?
Сейчас там и так
double
последним аргументом.В таких местах
float
не используется.В данной задаче это — необходимо?
По-моему, вы выдумываете несуществующие трудности.
Не понял мысли.
Вы, видимо, обознались.
Наверное, прежде чем "продавать" что-то сомнительное, следовало бы научиться пользоваться C++:
При попытке раскомментировать за'
if
'-0-енное, компилятор отказывается компилировать.Почему не было даже попыток применить данное решение?
Человек, утверждающий подобное, даже не пытался изучить предмет.
Не каждый эмитент имеет столько выпущенных акций.
Хорошо, пусть речь идёт о таком эмитенте, который выпустил столько или большее количество акций.
Очевидно, что обычный трейдер не обладает таким количеством акций, и чтобы их продать, их необходимо зашортить, то есть, сначала занять у брокера.
Вряд ли у брокера есть столько акций, но даже если есть, он не выдаст акции взаймы просто так, а — только под залог депозита или его части.
У подавляющего большинства трейдеров нет столько денег на депозите.
Хорошо, предположим, что и деньги есть, и у брокера есть необходимое количество акций.
Чтобы их продать, необходимо, чтобы их кто-то сразу купил, а для этого в биржевом "стакане" должны быть заранее выставлены лимитные заявки на покупку всего объёма продаваемых акций.
Очевидно, что это — весьма маловероятное событие.
Наконец, как правило у брокера в API есть ограничение на объём в одной торговой операции, которое значительно меньше 4294967196.
Но — зачем все эти тонкости, если можно просто ляпнуть о банкротстве?
Вместо всего этого, насколько я понимаю, была ссылка на авторитет.
Однако, авторитетов не существует, и каждый раз необходимо обосновывать, а не ссылаться на свой или чужой авторитет, что это кто-то авторитетный сказал, потому что каким бы ни был авторитетным человек, он может ошибиться.
Бесполезно продавать Rust, тем более, таким способом.
Зачем требовать от джуна-программиста требования знания электроники, тем более, аналоговой, которая на порядки сложнее в понимании, чем цифровая?
Ладно электроники, зачем от него требовать знания автомата Калашникова?
Может, ещё потребовать теоретические знания, связанные с артиллерией, включая детали, связанные с физикой выстрела и полёта снаряда, и заканчивая знаниями особенностей современных видов пороха и прочих взрывчатых веществ как с точки зрения химии, так и с точки зрения физики?
Есть такие люди, которые заявляют на много порядков бо́льшие требования, чем они есть на самом деле, и делают вид, что это и есть истинное положение вещей.
Сеньор-программист, наверное, тогда должен знать всю геологию, всю космическую область, включая особенности, связанные с релятивистскими эффектами, а также атомные технологии, применяющиеся как в атомной промышленности, так и в военной сфере. Бонусом будет знание теоретической физики и физики ядерных частиц. Да?
Нет.
Мы здесь — о реальности или о чьём-то восприятии?
Плюс-минус полгода-год — да.
А если на график смотреть, то можно и точнее.
И необязательно прямо самое дно ловить.
Результат, если поймать дно неточно, будет чуть похуже, но — явно лучше, чем войти прямо перед кризисом.
История рифмуется, большинство кризисов — циклические, примерные временны́е параметры таких кризисов известны, и они не отличаются в десятки раз.
Достаточно взглянуть на график, чтобы в этом убедиться.
Для этого не требуется инсайдерский доступ, всё есть на графиках.
Текущий кризис — не циклический, здесь всё будет по-другому происходить, но даже об этом информация есть в открытом доступе.
Если вам кажется, что раз вы чего-то не знаете, то и никто не может знать, то — да, давайте заканчивать.
Опять же, я — об общем случае, а не обо всех случаях.
Я не показал, что переполнение
int
'а возникает для любых случаев, зато показал, что возникает для одного конкретного.Очевидно, что этот конкретный случай — не единственный, есть ещё и другие случаи, для которых возникает переполнение.
Опять же, вы опровергаете не то, о чём я говорил.
Я не говорил, что проблема наличествует для всех случаев.
Ну, и что, что в каких-то конкретных случаях проблемы нет?
В общем-то случае проблема имеется.
Более того, некоторые LLM-ки это "видят" и даже пытаются "думать" в правильном направлении, хотя и с ошибками.
В частности по второй ссылке, которую привёл @izuck3n можно по строке "Integer overflow risk" обнаружить следующее:
Предложение от ChatGPT — неверное, но "ход мысли", в целом, верный.
Так что проблема не только имеется, но она ещё и не остаётся незамеченной некоторыми моделями.
И проблема будет проявляться в очень существенном количестве случаев, навскидку — в половине случаев, поэтому "не заметить" её будет нельзя.
Иногда проще получить ответ brute-force'ом, что я и сделал.
Можно не дёргать каждый раз
srand
, а выполнить его один раз вначале или вообще не выполнять ни разу, — результат получается одинаковый.Как видно, UB имеется в 83% случаев.
Игнорировать такой процент случаев — невозможно.
И правильный ответ — делает что угодно, ибо — UB.
А зачем — можно только гадать.
На языке C имеем UB в связи с переполнением
int
.Наблюдать можно здесь.
Average1 считается неверно для всех не-MSVC компиляторов.
Потому что библиотека использует для случайного числа весь доступный диапазон положительных значений типа
int
.Так вы и похвастались.
Если купить индекс на много лет, то как тут может не получиться, даже если купить прямо перед кризисом?
Просто менее эффективно, чем могло бы быть, если купить сразу после кризиса.
А вы знаете, какой силы потрясение ожидает рынки в ближайшие месяц-два-три?
Инвестировать следует аккурат сразу после кризиса, а не до.
Иначе — неэффективно получается: несколько лет ждать придётся, пока последующий рост перекроет падение в кризис.
И только потом пойдёт доход.
Посмотрите курс SP500 в 2008-ом году и в 2009-ом.
Ориентировочно, 1400 и 870.
И вернулся к 1400 только к 2012-ому году.
Если его купить в 2008-ом по 1400, то в 0 выйти удастся только к 2012-ому.
4 года ожидания выхода из убытков, и только потом начинает идти прибыль.
А если купить на год позже, в 2009-ом, по 870, то через 3 года, к 2012-ому, прибыль составит 61%. Ведь есть же разница?
То есть, лучше год подождать, пока всё упадет до дна, и тогда и инвестировать.
Правда, нынешний кризис — не такой, как предыдущие, неизвестно, когда рост начнётся. Не один год может пройти, и не два. Да и рынки могут кардинально поменяться.
Поэтому я сомневаюсь, что кто-то там велел сейчас инвестировать.