Pull to refresh
-5
0.1
Send message

Вы плохо говорите на с++, наверное потому что он не родной для вас.

Шаред поинтеров вы не знаете, одна из причин на уровне дизайна почему в нем 2 указателя перегрузка номер 8 https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

Но признаюсь честно, даже среди тех кто пишут на плюсах годами каждый день очень мало кто знает и понимает зачем это.

А нужно это именно для выражение композиции через владение значением по дефолту, но если нужно, то юник поинтер тоже можно использовать.

Ещё раз в плюсах композиция это по дефолту владение значением, есть причины когда это не желательно, тогда композиция выражается через владение юник поинтером.

Выши замечания, что владение по значению и/или юник поинтером не совместимы с шаред/вик поинтером - не состоятельны. Смотрите документацию, и сразу скажу я так делал и не раз. Единственное условие для этой техники это алокация рут объекта дерева объектов в хипе и владение этим рутом через шаред поинтер.

В плюсах все связи (агрегация/ассоциация) между объектами внутри одного дерева это просто сырые указатели. Потребность в вик поинтерах возникает только для ассоциации с объектом из другого дерева объектов.

Агрегация с независимым объектом (иммутабл в вашем случае) в плюсах выражается не через шаред поинтер(хотя конечно можно, но не нужно это как из пушки по воробьям), а через интрузив поинтер его в стандарте нет, но есть много где в других либах. Если агрегаты и объекты которые их агрегируют живут в одном потоке то счётчик может быть не атомарным, в общем случае нужен атомарный (но х86 разницы нет). В случае многопотока, имутабельность агрегатов позволяет обойтись только релаксед операциями на счётчике (заметьте что релакседы все равно атомарны по записи в память), а не более дорогой парой аквайр/релиз которая нужна только если объект мутабельный (чтобы как раз эти мутации гарантировано подтянулись в деструкторе).

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

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

они гораздо сложнее, чем "смещение на компайл тайм константу"

Ну как же, вот же асемблер, да проверка на нул, потом в ах грузится виртуальная таблица ИБ, для ИА тоже самое только константа будет 0, для какого нибудь ИС будет 16 и т.д. В сх грузится зис также смещенный на ту же константу. Проверку на нул не избежать и она у вас и так есть в виде оптионала. Мало того у вас в примере каст + виртуальный вызов, сделайте просто каст. При касте сместиться только зис и все (я не проверял, но ванную даже проверки на нул не будет).

Если храните базовые указатели (имеется в виду указатель на сам объект?)

Нет, имеется в виду, что если вам нужна виртуальность то никто не хранит указатели на конкретные типы, вместо этого хранятся указатели на интерфейсы/базовые классы. Это значит, что в вашем примере обдж не авто поинтер, а ИБ*.

Если хотите узнать сколько стоит каст, то тестить надо вот это, а не то что вы тестить

auto* obj = new Impl();

IB* base = obj;

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

Невидимых кастов никаких нет при использовании бэйз указателя.

будут по одному vmt_ptr на каждый отдельный реализованный интерфейс

Да.

будет движение this-указателя при кастах

Да, это движение тривиально, смещение на компайл тайм константу + касты редки. Ну т.е. когда вы пишите код который наследует вот таким образом, то вы и объекты храните в контейнерах сразу через базовый указатель, а иначе зачем это все.

двойной размер всех смарт-поинтеров

Это я не понял о чем вы, любой юник поинтер всегда один указатель, любой шаред поинтер зависит от реализации, но все с чем я реально сталкивался всегда 2 указателя(объект + делетер) + счётчик. И это так сделано совсем по другим причинам, это такой дизайн шаред поинтера.

сложная настройка объекта в конструкторе с заполнением всех этих vmt_ptr-полей

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

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

И ещё, вы тут много пишете про бест практисы, но я не очень понимаю как это у вас сочетается с оптимизацией перформанса динамик кастов. Я может отстал от жизни, но всегда считал динамик каст хаком, нарушением инкапсуляции, но готов посмотреть на ваш пример с рантайм "интроспекцией" (ну хак хаком же) где это по вашему уместно. Сразу скажу что в тех же растах у вас просто будет несколько контейнеров (а)рс где один и тот же объект боксится несколько раз по разным крэйтам и никаких динамик кастов не потребуется

Я вам ещё один хороший вопрос задам, а что на счёт сравнения вашей диспетчеризации с С++, но только наложите на с++ код те же ограничения что и у вас в языке - нет виртуального наследования, наследовать можно только одну реализацию и сколько угодно интерфейсов (классов без данных с виртуальными методами). Мне асемблер обычно не интересен и я туда не гляжу, но даётся мне что для компиляторов это первичный сценарий для оптимизаций и ставлю на то что в с++ для такого случая быстрее чем у вас.

Ну почему же, у меня вот специфическая задача, проверить перед загрузкой в память своего приложения, что мой плагин не пропатчен. Я пока вижу это так, генерирую пару пуб/приват ключи, хардкожу пуб ключ в бинарь своего приложения, подписываю приватным ключём свои сборки плагина. В приложении перед загрузкой плагина проверяю подпись с помощью захардкоженного пуб ключа. Зачем мне для этой задачи вся эта пки, какие доп гарантии это мне даст по сравнению с тем что я описал? Само приложение то будет подписано как надо, а вот плагин по простому. Приложение инсталится как положено, а вот плагин дестрибутится на флешках такова природа моего приложения.

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

Назад к топику, видится мне если такие высказывания не подподают под уголовку то Маск, я думаю, защищал бы. Говорить/думать/иметь мнение различное с мэйнстримным, но не делать ничего противозаконного и пострадать за это как раз то с чем Маск и обещает помочь.

Ну что сказать, у меня по сочинениям всегда была оценка 5, только это сумма из двух за грамматика и правильная речь. Меньше 10 ошибок в тексте на 500 слов никогда не было, и вы знаете что? Оказывается, в реальной жизни, с этим диагнозом можно жить, жить нормально и не лечится (хотя я пробовал лечится - таблетки не помогают), даже в России и уж тем более там где русский это иностранный язык, но это на самом деле распространяется и на другие языки.

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

Нарушения нарушению рознь, я так регулярно (да и вы тоже без исключений) какое нибудь пожелание правил нарушаю ежедневно. Ну например самое частое, две полосы в частном секторе с юнитами, с обоих сторон почти все запаркованно, т.к. не у всех есть парковка во дворе или не всем хватает или ещё какие причины. По правилам я должен машины объезжать и возвращаться в свою полосу если там есть место, да ещё и как новогодняя ёлка поворотниками мигать при каждом маневре, да ещё и заранее. Так НИКТО не делает, поворотниками не сигналят вообще потому что и так всем буквально очевидны ваши и чужие маневры, в свою полосу уходят только чтобы разъехаться со встречной машиной. Т.е. по факту дорога вмещает 3 полосы, 2 крайних заняты в случайных местах и есть одна центральная общая для обоих направлений, ни одни правила это адекватно не описывают и о ужас люди как-то сами справились без них. Я это к чему, я думаю что вы сильно переоцениваете значение правил это не законы физики, игнорирования которых фатально, а просто набор букв которые пытаются с ориентировать вас в МОДЕЛИРУЕМОЙ реальности.

  1. Довольно категорично, а на чем основываются ваши страхи? Есть прецеденты?

  2. Представим, что кожанным запретили управлять всеми машинами в вашей локации, чё и в этом сеттинге низя сворачивать? А если можно увернуться без существенного ущерба вообще, почему нет то?

  3. Вы вообще в курсе, что ПДД не полны и противоречивы, по определению, а из этого следует свобода выбора действий как минимум в редких кейсах, чё делать будем?

Т.е. повторный ран вернёт, токен который что? Комплетед как при кенселе? Или повторный ран кинет исключение? Это конечно вкусовщина, но все же явный мув для таска как то более идиоматичен. И я так подумал, и вижу что ваш токен без зена, по сути ни чем от стд футуры не отличается, я бы даже ее и возвращал, хотя возможно у вас там есть кэнсел и метод узнать про это. Вот вы писали статью про АПИ, а в этом примере ничего толком не показали т.к все декларации нужно самому додумывать, так не годится конечно.

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

Вообщем, опять же вкусовщина, но я вижу ровно 0 принципиальных отличий вашего дизайна от пары стд асинк/футура (ну разве что у вас ещё кэнсел завезли). Другими словами если я могу лэйзи собрать таск, то что мне мешает также лэйзи собрать все лямбды в одну а потом ее родную и отправить в асинк получить футуру и также ждать на ней? Даже больше, согласно вашим же рекомендациям именно так и нужно сделать, т.к. это добавляет ещё больше ортогональности, комбинировать лямбды может понадобиться и в отдельности от асинхронщины. А кэнселейшен токен (если нужен) можно через параметр лямбды передавать и потом через тупл вместе с рещультатам всем последующим лямбдам в цепочке.

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

А что делать в с вашим АПИ если лэйзи инициализация по какой то причине не вариант? Ну или более конкретно нужно поднасыпать зенов когда лягушку уже варят или уже сварили? А ещё точнее ваш АПИ нарушает ваше 1 правило, таск ран я могу вызвать несколько раз, могу добавить зенов после ран. По вашей лэйзи логике ран должен быть у пула и консумить таск и возвращать какой то токен на котором можно только ждать или спросить о готовности.

Как эксперт по плюсам хочу обозначить несколько неточностей с вашей стороны

С++ был спроектирован в эпоху однопоточности и с учётом этого важного контекста он обсалютно прекрасно поддерживает композицию. Дефолтный выбор для реализации композиции это родительский объект владеет дочерним по значению. Ассоциативная ссылка как и у вас это вик поинтер, агрегатная ссылка это забыл точное название из буста, смарт поинтер на объект со внутренним счётчиком ссылок. Как так, спросите вы, композит же это значение как создать вик поинтер на значение? Да очень просто рутовый объект должен реализовывать шаред фром зис, а все дочерние объекты используют его счётчик при создании ассоциативной ссылки. Это та редко используемая специализация конструктора стд шаред поинтер о которой мало кто знает и совсем мало кто понимает как это работает и зачем это нужно. Вот именно для этого оно и нужно.

У вас есть единственное разумное возражение - полиморфизм. Да в таком случае композит это шаред поинтер, а ассоциативная ссылка на него вик поинтер, но есть альтернатива известная ещё с античных(си) времён - полиморфизм на вариантах или полиморфизм в функциональном стиле. Это когда рут объект имеет по значению правильно выравненный достаточного (для хранения любого возможного полиморфного типа) размера массив байт + дескриминатор. Полиморфные объекты размещаются внутри этого массива через инплэйс нью.

Глубокое копирование при использовании значений для агрегатов идёт почти из коробки, да ассоциативные ссылки внутри одного дерева объектов нужно поправить руками в конструкторе/присваивании после копирования.

Что я хочу сказать, с++ позволяет сделать все по уму почти из коробки, да как это делать правильно и не ошибаться понимают мало людей, но ваше заявление что в плюсах это всегда русская рулетка основано на недостаточных знаниях о с++.

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

Общая очередь это деталь реализации тред пула, проблема у вас в языке, чтобы что то кому то послать нужно знать адресата, а в модели пол у нас нет адресата, поэтому она (согласно изложенному в статье) на данный момент не реализуема. Это архитектурное ограничение вашего языка.

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

Конкретно в вашей модели памяти операция лок для ассоциативной ссылки должна возвращать не опшионал стэковой ссылки, а корутину которая возвращает стэковою ссылку.

авэйт на такой корутине спрячет пересылку таска в поток владелец, заморозку объекта и отправку его назад в поток который лочит ссылку, это то как вы это видите сейчас. С точки зрения плюсовика это конечно очень много накладных расходов, но в целом рабочий вариант. Но есть альтернатива которая прекрасно работает под той же абстракцией корутин, юзер мод средства синхронизации. На самом деле нет вселенской необходимости слать асинхронный таск обрабатывать его и так же слать ответ просто что бы получить доступ к данным, можно заложить объект сделать глубокую копию и разложить обьект, копию отдать тому кто лочит ассоциативную ссылку. Это намного эффективнее чем асинхронные таски, но требует корутин, т.к. лок ассоциативной ссылки может привести к юзер мод блокировке.

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

Конечно есть, модель пол. Сейчас уточню. У вас описана модель пуш, поток посылает асинхронный таск в mpsc очередь другого потока, тот таск исполняет и таким же образом посылает результат первому потоку в его очередь. Пол работает наоборот. У меня есть поток который генерирует таски и кладет их в СВОЮ spmc очередь, а другие потоки забирают таски на обработку из этой очереди, а результат кладут в свою очередь, первый(хотя чаще ещё какой то) поток периодически опрашивает очереди рабочих потоков на предмет результата.

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

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

Есть у нас в проекте такое, вик поинтер в кэше, если объект уже сдох то пересоздаем если нет отдаем, работает нормально только либо для иммутабл объектов либо в одном потоке. И знаю я это потому, что как раз очень серьезные проблемы у нас с этим с мутабельными объектами в многопотоке. Одно спасает, случается редко и краши пока не преодолели порог что бы их фиксить.

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

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

Вижу новые возможности для "бизнеса" - услуги регистрации на российских ресурсах. Берём человека не обремененного заботами и заводим на него аккаунт на том ресурсе где нужно. Меняем в аккаунте почту на почту заказчика услуг. Я не юрист, но вроде закон про регистрацию, а не авторизацию, ну так будут соблюдать регистрацию, а авторизовываться как удобно/надо. В законе нет запрета на 100500 аккаунтов на одного и того же человека. Думаю будет как с впн, большинство без впн, и тут большинство будет по своим перс данным зарегано, а кто захочет воспользуется услугой регистрации.

Information

Rating
2,499-th
Registered
Activity