Здравствуйте, Тёмчик, Вы писали:
S>>Сперва прочитайте то, что вам пишут, потом уже отвечайте.
Тё>OMG да я понял, что вы давно слились, когда запели про "10 подписок".
Тё>Реалтайм бывает soft и hard. Soft вообще похрен на чём делать, а для hard плюсы не подходят (если не рассматривать C с классами).
Т.е. когда вас прижали к стенке вашей же цитатой, то вы переобуваетесь и признаете, что речь таки шла про рилтайм. ЧТД.
S>>Тёмчик, давайте говорить о примере от B0FEE664. В котором под T можно подразумевать только std::pair<OnPress, void*>. Если вы хотите ввести в обсуждение еще что-то, то потрудитесь это описать, чтобы люди понимали, о чем речь. Тё>Почему у вас onpress в типе? Почему у вас void*? Вы что, про статическую типизацию не слыхали?
Это не у меня. Это у человека, который написал пример, приведенный B0FEE664. А тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы).
S>>Т.е. вы для хранения списка подписок предлагаете хранить еще и специальный sentinel node? Тё>Я не "предлагаю" — это оптимизация связного списка для упрощения его операций, почитайте, учиться ведь всегда полезно.
Так ведь я не про упрощение, а про связанные с этим расходы.
S>>Подписчик. Тё>Ну вот ваш подписчик должен хранить интерфейс для отписки. Может хранить пачку таких подписок в списке, и отписываться в деструкторе, например.
Или он просто хранит у себя указатель на Button и вызывает RemoveOnButtonPress в нужных ему местах.
S>>На словах все герои. Только вот если у вас отписка работает через поиск (по указателю на callback или по какому-то уникальному Id), то она оказывается более устойчивой к подобным ошибкам. Тё>Т.е. вы смирились с фактом, что в вашем говнокоде нет определённости, придёт отписка дважды, или вообще не придёт. И поэтому вы городите тормозной кривой код, оправдывая это порно "локальным кэшем".
Мой говнокод, в отличии от вашего идеального, свободно лежит в открытом доступе. И любой желающий может посмотреть и сделать выводы. В отличии от.
Тё>Возвращается ссылка на интерфейс Subscription. Это может быть наследник от Node имплементирующий Subscription. О каком каком копировании вы поёте?
Тёмчик, мы же про C++ говорим, здесь вы не можете вернуть "интерфейс". Вам нужно возвращать либо экземпляр конкретного класса (и тогда сталкиваться с проблемой копирования экземпляров), либо возвращать (умный) указатель на реализацию интерфейса со всеми вытекающими для этого последствиями.
Здравствуйте, Тёмчик, Вы писали:
S>>Гораздо более серьезно, чем когда вы заявляете, что C++ не используется для рилтайма. Тё>Я заявлял, что в ядре не место C++.
Артёмка, сколько production kernel кода ты написал?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Небольное количество подписчиков яйца выеденного не стоит. Можете их хоть квадратично перебирать
S>>>Вы заявили следующее (http://rsdn.org/forum/job/7907304.1):
Тё>>Реалтайм бывает soft и hard. Soft вообще похрен на чём делать, а для hard плюсы не подходят (если не рассматривать C с классами).
S>Т.е. когда вас прижали к стенке вашей же цитатой, то вы переобуваетесь и признаете, что речь таки шла про рилтайм. ЧТД.
Признаю диванное поражение от более умелого бойца.
S>>>Тёмчик, давайте говорить о примере от B0FEE664. В котором под T можно подразумевать только std::pair<OnPress, void*>. Если вы хотите ввести в обсуждение еще что-то, то потрудитесь это описать, чтобы люди понимали, о чем речь. Тё>>Почему у вас onpress в типе? Почему у вас void*? Вы что, про статическую типизацию не слыхали?
S>Это не у меня. Это у человека, который написал пример, приведенный B0FEE664. А тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы).
Про интеграцию с чужим API — почитайте про https://en.wikipedia.org/wiki/Visitor_pattern
S>>>Т.е. вы для хранения списка подписок предлагаете хранить еще и специальный sentinel node? Тё>>Я не "предлагаю" — это оптимизация связного списка для упрощения его операций, почитайте, учиться ведь всегда полезно.
S>Так ведь я не про упрощение, а про связанные с этим расходы.
Вот и подумайте про сокращение "C" в формуле C*O(...). Никто вам в C++ не помешает разместить sentinel node в поле цикличного списка по значению.
S>>>Подписчик. Тё>>Ну вот ваш подписчик должен хранить интерфейс для отписки. Может хранить пачку таких подписок в списке, и отписываться в деструкторе, например.
S>Или он просто хранит у себя указатель на Button и вызывает RemoveOnButtonPress в нужных ему местах.
Блиииин ну это же рафинированный говнокод.
S>>>На словах все герои. Только вот если у вас отписка работает через поиск (по указателю на callback или по какому-то уникальному Id), то она оказывается более устойчивой к подобным ошибкам. Тё>>Т.е. вы смирились с фактом, что в вашем говнокоде нет определённости, придёт отписка дважды, или вообще не придёт. И поэтому вы городите тормозной кривой код, оправдывая это порно "локальным кэшем".
S>Мой говнокод, в отличии от вашего идеального, свободно лежит в открытом доступе. И любой желающий может посмотреть и сделать выводы. В отличии от.
Я не обсуждал в этой ветке ваш репозиторий. Сконцентрируйтесь.
Тё>>Возвращается ссылка на интерфейс Subscription. Это может быть наследник от Node имплементирующий Subscription. О каком каком копировании вы поёте?
S>Тёмчик, мы же про C++ говорим, здесь вы не можете вернуть "интерфейс". Вам нужно возвращать либо экземпляр конкретного класса (и тогда сталкиваться с проблемой копирования экземпляров), либо возвращать (умный) указатель на реализацию интерфейса со всеми вытекающими для этого последствиями.
Тё>Небольное количество подписчиков яйца выеденного не стоит. Можете их хоть квадратично перебирать
Грубо говоря, у вас может быть по 2-3 подписчика на каждый условный Button, и 100500 этих самых условных Button-ов.
S>>Это не у меня. Это у человека, который написал пример, приведенный B0FEE664. А тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы). Тё>Про интеграцию с чужим API — почитайте про https://en.wikipedia.org/wiki/Visitor_pattern
Каким боком здесь Visitor?
S>>>>Т.е. вы для хранения списка подписок предлагаете хранить еще и специальный sentinel node? Тё>>>Я не "предлагаю" — это оптимизация связного списка для упрощения его операций, почитайте, учиться ведь всегда полезно.
S>>Так ведь я не про упрощение, а про связанные с этим расходы. Тё>Вот и подумайте про сокращение "C" в формуле C*O(...).
Это вы возьмите и подсчитайте. У вас и так на каждый POD с двумя указателями приходится еще три указателя + MCB + выравнивание. К этому давайте приплюсуем еще и расходы на sentinel node. Получается не так уж и мало для контейнера для нескольких элементов. И если этих самых контейнеров в программе овердофига, то...
А ну да, у TS-еров, как и у JS-еров же память же не ресурс же.
S>>Или он просто хранит у себя указатель на Button и вызывает RemoveOnButtonPress в нужных ему местах. Тё>Блиииин ну это же рафинированный говнокод.
Это зависит. Если подписчик при этом всем еще и оказывается единственным владельцем Button-а, то ему можно об отписках вообще не парится.
S>>>>На словах все герои. Только вот если у вас отписка работает через поиск (по указателю на callback или по какому-то уникальному Id), то она оказывается более устойчивой к подобным ошибкам. Тё>>>Т.е. вы смирились с фактом, что в вашем говнокоде нет определённости, придёт отписка дважды, или вообще не придёт. И поэтому вы городите тормозной кривой код, оправдывая это порно "локальным кэшем".
S>>Мой говнокод, в отличии от вашего идеального, свободно лежит в открытом доступе. И любой желающий может посмотреть и сделать выводы. В отличии от. Тё>Я не обсуждал в этой ветке ваш репозиторий. Сконцентрируйтесь.
Если вы не обсуждаете мой репозиторий и мой код, то вы не можете говорить о моем говнокоде. Моего кода здесь нет. Глаза разуйте.
Тё>>>Возвращается ссылка на интерфейс Subscription. Это может быть наследник от Node имплементирующий Subscription. О каком каком копировании вы поёте?
S>>Тёмчик, мы же про C++ говорим, здесь вы не можете вернуть "интерфейс". Вам нужно возвращать либо экземпляр конкретного класса (и тогда сталкиваться с проблемой копирования экземпляров), либо возвращать (умный) указатель на реализацию интерфейса со всеми вытекающими для этого последствиями.
Тё>https://en.cppreference.com/w/cpp/language/abstract_class
Ну так почитайте сами. Вы не можете создавать экземпляры абстрактных классов. Только конкретных. Соответственно, с абстрактными классами вы можете работать только на уровне ссылок/указателей. И если вы возвращаете ссылку на абстрактный класс, то возникает вопрос: а где живет конкретная реализация и кто контролирует ее время жизни. Отвечая на этот вопрос вы и придете к необходимости возвращать (умный) указатель на реализацию интерфейса.
Здравствуйте, so5team, Вы писали:
S> кто контролирует ее время жизни. Отвечая на этот вопрос вы и придете к необходимости возвращать (умный) указатель на реализацию интерфейса.
unsubscribe() мешает благородному дону удалить instance?
S>Но для этого в C++ немного понимать нужно.
Слушайте, меня конкретно уже разрывает на вашу узколобость в сочетании наскоками на моё знание C++. Вот такие представители профессии и создают негативный стереотип о C++- ках. Это не относится к действительно прокачанным программистам (как Зудин), которые в силу обстоятельств применяют C++ как инструмент.
Вы не ответили на вопрос о том, каким боком и зачем бы приплетен паттерн Visitor.
S>> кто контролирует ее время жизни. Отвечая на этот вопрос вы и придете к необходимости возвращать (умный) указатель на реализацию интерфейса. Тё>unsubscribe() мешает благородному дону удалить instance?
У меня пока проблема в том, чтобы разобраться с предложенным вами вариантом. Т.е. понять, что это за вариант вообще.
Пока что вырисовывается приблизительно такая картина:
template<typename T>
class SubscriptionStorage {
public:
struct Unsubscription {
virtual ~Unsubscription() = default;
virtual void unsubscribe() noexcept = 0;
};
[[nodiscard]]
Unsubscription * subscribe(T && value);
...
private:
struct Link {
virtual ~Link() = default;
Link * prev_;
Link * next_;
};
struct OneSubscription : public Link, public Unsubscription {
T payload_;
...
void unsubscribe() override {
... // Вычеркивание из списка.delete this; // Уничтожение узла.
}
}
Link sentinel_;
};
template<typename T>
Unsubscription * SubscriptionStorage::subscribe(T && value) {
return new OneSubscription(std::move(value), ...);
}
S>>Но для этого в C++ немного понимать нужно. Тё>Слушайте, меня конкретно уже разрывает на вашу узколобость в сочетании наскоками на моё знание C++. Вот такие представители профессии и создают негативный стереотип о C++- ках.
-- Этот ваш C++ говно и для разработки реал-тайма не применяется!
-- А ты хоть C++ знаешь?
-- Да!
-- Что такое виртуальный деструктор?
-- Какой ты токсичный! Из-за таких как вы и C++ сообщество считается токсичным!
Тё>Это не относится к действительно прокачанным программистам (как Зудин), которые в силу обстоятельств применяют C++ как инструмент.
Мне как-то фиолетово, насколько прокачанным вы считаете меня, но таки применяю C++ как инструмент. Т.к. в области интересных для меня задач до недавнего времени широко использовались только C и C++, где-то еще была Ada. Сейчас вот Rust подвезли. Но до настоящего мейнстрима Rust-у еще нужно добираться лет 5.
Здравствуйте, so5team, Вы писали: S>Вы не ответили на вопрос о том, каким боком и зачем бы приплетен паттерн Visitor.
S> тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы).
Почитайте про Visitor, подумайте. S>>> кто контролирует ее время жизни. Отвечая на этот вопрос вы и придете к необходимости возвращать (умный) указатель на реализацию интерфейса. Тё>>unsubscribe() мешает благородному дону удалить instance? S>У меня пока проблема в том, чтобы разобраться с предложенным вами вариантом. Т.е. понять, что это за вариант вообще. S>Пока что вырисовывается приблизительно такая картина:
sentinel иницировать в конструкторе:
sentinel.next = sentinel.prev = sentinel.
Можно ещё поиграться с пре-инициализацией кэша SubscriptionNode как цикличного списка, и чтобы ObservableImpl брал Node оттуда в свой список, а при unsubscribe возвращал обратно. Будет тебе тогда cache locality и избежание динамического выделения памяти:
SubscriptionNode[2048] nodeCache;
S>>>Но для этого в C++ немного понимать нужно. Тё>>Слушайте, меня конкретно уже разрывает на вашу узколобость в сочетании наскоками на моё знание C++. Вот такие представители профессии и создают негативный стереотип о C++- ках. S>
S>-- Этот ваш C++ говно и для разработки реал-тайма не применяется!
S>-- А ты хоть C++ знаешь?
S>-- Да!
S>-- Что такое виртуальный деструктор?
S>-- Какой ты токсичный! Из-за таких как вы и C++ сообщество считается токсичным!
Ну вот для вас виртуальный деструктор- верх сложности? О чём я и говорил: слабость в алгоритмах и религиозная вера в C++. Тё>>Это не относится к действительно прокачанным программистам (как Зудин), которые в силу обстоятельств применяют C++ как инструмент. S>Мне как-то фиолетово, насколько прокачанным вы считаете меня, но таки применяю C++ как инструмент. Т.к. в области интересных для меня задач до недавнего времени широко использовались только C и C++, где-то еще была Ada. Сейчас вот Rust подвезли. Но до настоящего мейнстрима Rust-у еще нужно добираться лет 5.
Я вообще много чем занимался, и нигде из компаний, не являлся C++ рационально обоснованным инструментом. Только исторически или в силу религии.
Здравствуйте, Тёмчик, Вы писали:
S>>Вы не ответили на вопрос о том, каким боком и зачем бы приплетен паттерн Visitor. Тё>
S>> тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы).
Тё>Почитайте про Visitor, подумайте.
Читал. Думал. Пока получается, что Тёмчик звиздун, который звиздит не думая, а потом не может за свой звиздежь ответить.
Так как Visitor поможет в интеграции с C-шным кодом.
Тё>Unsubscription => Subscription (подписка) Тё>SubscriptionStorage => ObservableImpl Тё>Link => Node Тё>OneSubscription => SubscriptionNode
Очень веские замечания, да. При том, что Link принципиально сделан как Link, а не как Node. Обратите внимания, что Link кроме ссылок ничего не содержит.
Тё>sentinel иницировать в конструкторе: Тё>sentinel.next = sentinel.prev = sentinel.
За такие инициализации в конструкторе в C++ со времен 1990-х по рукам бъют. Но откуда вам знать-то.
Тё>Можно ещё поиграться с пре-инициализацией кэша SubscriptionNode как цикличного списка, и чтобы ObservableImpl брал Node оттуда в свой список, а при unsubscribe возвращал обратно. Будет тебе тогда cache locality и избежание динамического выделения памяти: Тё>
Тё>SubscriptionNode[2048] nodeCache;
Тё>
Тёмчик, да вы мало того, что зведун, так еще и архитектор-астронавт? Предложить мутную и сложную схему с большими накладными расходами и звиздеть, что это правильный дизайн.
Теперь становятся более понятными ваши стенания о том, что ваш звиздатый код не понимают, а вас не ценят.
Тё>Ну вот для вас виртуальный деструктор- верх сложности?
Нет, это вы не можете подтвердить свое знание C++. Без чего ваши отзывы и о возможностях C++, и о сфере применимости C++ играют очень яркими красками.
Тё>О чём я и говорил: слабость в алгоритмах и религиозная вера в C++.
Мне вот интересно, где именно в нашем с вами споре в этой теме вы нашли религиозную веру в C++ в моих словах. Пальцем показать сможете?
Тё>Я вообще много чем занимался, и нигде из компаний, не являлся C++ рационально обоснованным инструментом. Только исторически или в силу религии.
Здравствуйте, Lexey, Вы писали:
S>>Сказал как отрезал.
L>Это для него характерно. Раньше он свою упоротость демонстрировал, в основном, в автомобильной тематике. Теперь и до плюсов добрался.
Да он вроде по всем темам такой, от языков программирования до фотоаппаратов с автомобилями. А к плюсам, скорее, вернулся
Здравствуйте, so5team, Вы писали:
S>>>Вы не ответили на вопрос о том, каким боком и зачем бы приплетен паттерн Visitor. Тё>>
S>>> тому человеку, возможно (и скорее всего) нужно было в качестве callback-ов использовать чисто сишные функции. А это может потребоваться по разным причинам, начиная от использования легаси-кода и заканчивая интеграцией C++ного кода и кода на каком-нибудь Lua или Python (из которых наружу торчат C-шные интерфейсы).
Тё>>Почитайте про Visitor, подумайте.
S>Читал. Думал. Пока получается, что Тёмчик звиздун,
Похоже, что не понял. Не обучаем. Отказать.
S>который звиздит не думая, а потом не может за свой звиздежь ответить.
Готов ответить за звиздёж в любое время. Прилетайте в Сидней (может я и долечу когда нить до Бабруйска- но это врядли), я отвечу.
S>Так как Visitor поможет в интеграции с C-шным кодом.
Читайте ещё раз. Хотя, кому я это пишу. Вы упоротый по самые помидоры.
Тё>>Unsubscription => Subscription (подписка) Тё>>SubscriptionStorage => ObservableImpl Тё>>Link => Node Тё>>OneSubscription => SubscriptionNode
S>Очень веские замечания, да. При том, что Link принципиально сделан как Link, а не как Node. Обратите внимания, что Link кроме ссылок ничего не содержит.
Что это за словесный понос? Попробуйте меньше пить.
Тё>>sentinel иницировать в конструкторе: Тё>>sentinel.next = sentinel.prev = sentinel.
S>За такие инициализации в конструкторе в C++ со времен 1990-х по рукам бъют. Но откуда вам знать-то.
Я не писал в 90х на плюсах. Примерно 2001-2011.
Тё>>Можно ещё поиграться с пре-инициализацией кэша SubscriptionNode как цикличного списка, и чтобы ObservableImpl брал Node оттуда в свой список, а при unsubscribe возвращал обратно. Будет тебе тогда cache locality и избежание динамического выделения памяти: Тё>>
Тё>>SubscriptionNode[2048] nodeCache;
Тё>>
S>Тёмчик, да вы мало того, что зведун, так еще и архитектор-астронавт? Предложить мутную и сложную схему с большими накладными расходами и звиздеть, что это правильный дизайн.
Где там большие накладные расходы? Я уже указывал про "отдельных представителей профессии". Мастурбируете на шаблоны, но простейшие структуры данных для вас — "мутно" и "сложно".
S>Теперь становятся более понятными ваши стенания о том, что ваш звиздатый код не понимают, а вас не ценят.
Упоротых много развелось и не только в C++.
Тё>>Ну вот для вас виртуальный деструктор- верх сложности?
S>Нет, это вы не можете подтвердить свое знание C++. Без чего ваши отзывы и о возможностях C++, и о сфере применимости C++ играют очень яркими красками.
Это вы по виртуальному деструктору определили? Сами у себя спросили, сами ответили. Вы настолько упоротый, что не понимаете, что виртуальный деструктор это как 2+2. Вы остановились в развитии когда, в 1990 году?
Тё>>О чём я и говорил: слабость в алгоритмах и религиозная вера в C++.
S>Мне вот интересно, где именно в нашем с вами споре в этой теме вы нашли религиозную веру в C++ в моих словах. Пальцем показать сможете?
Действительно, сложно разобрать, где религиозная вера в C++, а где просто упоротость.
Тё>>Я вообще много чем занимался, и нигде из компаний, не являлся C++ рационально обоснованным инструментом. Только исторически или в силу религии.
S>Сказал как отрезал.
Здравствуйте, Lexey, Вы писали:
BFE>>>>Зачем? К тому же, если эти данные нужны, то их можно положить в то, что скрывается за void*. УК>>>Затем, что во многих ситуациях я хочу оперировать с данными контрола в коллбеке ивента, BFE>>Для этого есть void* L>void* для этого хреново подходит, ибо один и тот же обработчик может обрабатывать несколько кнопок. Нет, можно, конечно, при подписке передавать разные контексты, но потом их придется разруливать внутри обработчика, что явно не упростит его код. Данные об источнике (кнопке) и контексте обработчика, действительно, удобнее передавать раздельно.
Если один и тот же обработчик обрабатывает события от разных кнопок, то ему не важно, от какой конкретно кнопки пришёл вызов. Если же вызовы различаются, то нет смысла делать один обработчик, чтобы потов внутри различать кнопки. Но даже если вам нужно что-то экзотическое, то вам ничего не мешает под void* положить пару указателей Botton*, OtherData* и дальше работать точно так же.
УК>>>например сделать кнопку неактивной, BFE>>Вы собираетесь делать кнопку неактивной в callback в момент её нажатия? Вы понимаете, к чему это скорее всего приведёт? L>Вполне вероятно, что ни к чему плохому. Возможный сценарий: нажали кнопку Abort, в обработчике мы ее деактивируем и запускаем диалог с прогрессом отката.
Но все другие обработчики, добавленные после вызванного, получат вызов для неактивной кнопки, а это нарушение предусловий вызова.
УК>>> отписаться от события итд итп. BFE>>Т.е. вы собираетесь вызвать Button::RemoveOnButtonPress() метод внутри callback'а? Я вас правильно понимаю? Вы хорошо подумали? L>Для кнопок это несколько странный сценарий, но, гипотетически возможный. Например, нужно в обработчике дождаться нажатия нескольких кнопок (в любом порядке). Получили одно нажатие, отписались, ждем остальных. Если же забыть про кнопки, то это вполне типичный сценарий ожидания результатов нескольких операций.
Только вот при вызове Button::RemoveOnButtonPress() внутри callback'а скорее всего получится segmentation fault или другое UB: ведь в момент вызова callback'а внутри прохода std::for_each будет удалён объект на который указывает текущий итератор.
УК>>> Положить можно в void, только зачем заставлять пользователя библиотеки реализовывать стандартную для любой UI библиотеки машинерию? BFE>>Заставлять не надо и это не стандартная схема. L>Схема вполне стандартная.
Обычно нужен один обработчик на одну кнопку, а если нужно больше, то внутри обработчика уже можно организовать так, как хотите.
BFE>>>>Вообще-то void* — это нечто прямо противоположное к прозрачному, это полностью скрытые данные или интерфейсы о которых ничего не известно. L>Ничего неизвестно на стороне, генерирующей события. Но, на ней и не нужно ничего знать про внутреннее устройство того, что лежит под void*.
Согласен, иногда непрозрачность == изолированность полезна, но в том-то и дело, что это именно непрозрачность.
BFE>>Вот именно, что C, а не C++. В С++ всё иначе должно быть. L>В случае UI соглашусь. Но, подобные схемы не только для него используются. И, иногда, абстракции типа std::function или интерфейса с виртуальным методом в качестве колбэка могут быть слишком дороги по сравнению с обычной функцией, принимающей void*.
В данном случае ни о какой скорости речи не идёт.
Как удобно: когда по делу сказать нечего, то нужно наговорить собеседнику кучу гадостей.
Вот реально не понимаю, как паттерн Visitor поможет при работе с C API. Ладно бы еще какой-нибудь Facade был упомянут, ну или Bridge хотя бы, но Visitor... Просветите старика, плиз.
По поводу накладных расходов все было уже расписано ранее, перечитайте. По поводу "мутно", если вам не понятно, то речь шла про понятность политки владения сущностями в вашем подходе. В C++ сборщика мусора нет. Возвращать голые владеющие указатели так себе способ.
PS.
> Готов ответить за звиздёж в любое время.
Видели:
>> Реалтаймовые системы не на плюсах делают.
Здравствуйте, so5team, Вы писали:
S>Да он вроде по всем темам такой, от языков программирования до фотоаппаратов с автомобилями. А к плюсам, скорее, вернулся
Очевидно же, что сходил на собеседование, где ему объяснили, что плюсы он не только забыл, но в общем-то никогда и не знал.
Теперь "объясняет", что плюсы не нужны.
Здравствуйте, so5team, Вы писали:
S>По поводу "мутно", если вам не понятно, то речь шла про понятность политки владения сущностями в вашем подходе. В C++ сборщика мусора нет. Возвращать голые владеющие указатели так себе способ.
Похоже, для того, чтобы разрешить должным образом проблемы владения (т.е. чтобы было безразлично, что именно удаляется первым -- тот, кто делает подписки или же сам SubscriptionStorage) нужно использовать что-то вроде:
template<class T>
class SubscriptionStorage {
public:
struct Subscription {
virtual ~Subscription() = default;
};
using SubscriptionHandle = std::unique_ptr<Subscription>;
[[nodiscard]]
SubscriptionHandle subscribe(T && value);
... // Конструктор и прочий фарш не показаны.private:
struct Link {
virtual ~Link() = default;
Link * prev_;
Link * next_;
};
struct Internals : public std::enable_shared_from_this<Internals> {
Link sentinel_;
};
using InternalsShptr = std::shared_ptr<Internals>;
struct OneSubscription : public Link, public Subscription {
InternalsShptr internals_;
T value_;
OneSubscription(InternalsShptr internals, T && value)
: internals_{std::move(internals)}, value_{std::move(value)}
{}
~OneSubscription() override {
... // Вычеркивание себя из списка.
}
};
InternalsShptr internals_;
...
};
template<typename T>
SubscriptionStorage<T>::SubscriptionHandle SubscriptionStorage<T>::subscribe(T && value) {
auto result = std::make_shared<Subscription>(internals, std::move(value));
... // Провязывание новой подписки в список.return result;
}
Вот в этом случае, КМК, не будет проблем с временами жизни. Пока живет хотя бы одна подписка, остается живым объект SubscriptionStorage::Internals. Следовательно, деструкторы Subscription могут спокойно вычеркивать себя из списка подписок даже если сам объект SubscriptionStorage прекратил свое существование. С другой стороны, если все объекты Subscription разрушаются до того, как умрет SubscriptionStorage, то вообще никаких проблем: ссылка на SubscriptionStorage::Internals останется только у SubscriptionStorage и этот Internals умрет сразу вслед за SubscriptionStorage.
Для уничтожения подписки достаточно просто "потерять" SubscriptionHandle. Или явно вызвать для него reset.
С другой строны, если SubscriptionHandle нигде не сохранить, то подписка исчезнет сразу же после создания.
Ну и в рамках C++98, где не было возможности создавать Movable+NonCopyable классы, пришлось бы, скорее всего, делать SubscriptionHandle в виде аналога shared_ptr.
Еще в этом подходе коряво то, что при движении по списку подписок нужно будет делать либо dynamic_cast от Link-а к OneSubscription, либо вообще, если RTTI под запретом, пользоваться reinterpret_cast-ом (вроде бы static_cast здесь не прокатит). В общем-то, опасности в reinterpret_cast-е здесь не видно, но сам по себе код с такими кастами попахивает.
Здравствуйте, B0FEE664, Вы писали:
BFE>Если один и тот же обработчик обрабатывает события от разных кнопок, то ему не важно, от какой конкретно кнопки пришёл вызов.
Это еще почему? Ну и, замени кнопки на textbox'ы, например, и картина точно изменится.
BFE>Если же вызовы различаются, то нет смысла делать один обработчик, чтобы потов внутри различать кнопки.
Есть. DRY называет. Если код обработчиков практически идентичен, то зачем плодить лишние сущности?
BFE>Но даже если вам нужно что-то экзотическое, то вам ничего не мешает под void* положить пару указателей Botton*, OtherData* и дальше работать точно так же.
Я про такую возможность говорил, только это потенциальное усложнение логики каждого обработчика. Не думаю, что оно тут оправдано.
BFE>Но все другие обработчики, добавленные после вызванного, получат вызов для неактивной кнопки, а это нарушение предусловий вызова.
Это вопрос того, какие гарантии предоставляет автор механизма событий. И он совсем обязан гарантировать, что между нажатием на кнопку и вызовом обработчика состояние кнопки не может измениться.
BFE>Только вот при вызове Button::RemoveOnButtonPress() внутри callback'а скорее всего получится segmentation fault или другое UB: ведь в момент вызова callback'а внутри прохода std::for_each будет удалён объект на который указывает текущий итератор.
Это легко обходится через копирование колбэков во временный контейнер и вызов for_each поверх него. Это довольно стандартное решение для ситуаций, когда возможны описки из колбэков.
BFE>Обычно нужен один обработчик на одну кнопку, а если нужно больше, то внутри обработчика уже можно организовать так, как хотите.
Тем не менее, в тех же винформах в .NET там обычный event, на который можно вешать сколько угодно обработчиков. Так явно проще, чем писать кастомные обработчики, раскидывающие события по своим вторичным подписчикам.
BFE>В данном случае ни о какой скорости речи не идёт.
Здравствуйте, so5team, Вы писали:
S>Как удобно: когда по делу сказать нечего, то нужно наговорить собеседнику кучу гадостей.
S>Вот реально не понимаю, как паттерн Visitor поможет при работе с C API. Ладно бы еще какой-нибудь Facade был упомянут, ну или Bridge хотя бы, но Visitor... Просветите старика, плиз.
Дано: одно или несколько сторонних API. Нужно: сделать бесшовную интеграцию. Передаём visitor на нужное API. Это широко используемая практика в обработке данных от пачки разных API разных версий.
S>По поводу накладных расходов все было уже расписано ранее, перечитайте. По поводу "мутно", если вам не понятно, то речь шла про понятность политки владения сущностями в вашем подходе. В C++ сборщика мусора нет. Возвращать голые владеющие указатели так себе способ.
Можете сделать умный указатель для subscription. Да, C++ это боль.
S>PS.
>> Готов ответить за звиздёж в любое время.
S>Видели:
>>> Реалтаймовые системы не на плюсах делают.
S>Ответили за звиздеж, да.
Не на плюсах. Вот вы влезли в тему событийной модели, которой я сейчас плотно занимаюсь (использую RxJs). Я указал вас ссылку, что использовать вместо кривого велопеда — RxCpp.
Читайте и просвещайтесь. Может быть, в вашей области событий нет, отсюда и пустота в голове.
Здравствуйте, so5team, Вы писали:
S>Вот в этом случае, КМК, не будет проблем с временами жизни. Пока живет хотя бы одна подписка, остается живым объект SubscriptionStorage::Internals. Следовательно, деструкторы Subscription могут спокойно вычеркивать себя из списка подписок даже если сам объект SubscriptionStorage прекратил свое существование. С другой стороны, если все объекты Subscription разрушаются до того, как умрет SubscriptionStorage, то вообще никаких проблем: ссылка на SubscriptionStorage::Internals останется только у SubscriptionStorage и этот Internals умрет сразу вслед за SubscriptionStorage.
Да просто используй std::unique_ptr с кастомным Deleter.
На самом деле, этот геморрой с хранением Subscription и последующим удалением не нужен при использовании Observable из ReactiveX: там есть оператор takeUntil. Везде в во все цепочки подписок вставить takeUntil(onDestroy$). onDestroy$ — это Subject, который один раз вызывает onDestroy$.next(); onDestroy$.close(), и все подписки магичеким образом само-разрушаются.
S>Для уничтожения подписки достаточно просто "потерять" SubscriptionHandle. Или явно вызвать для него reset.
S>С другой строны, если SubscriptionHandle нигде не сохранить, то подписка исчезнет сразу же после создания.
Вы явно не работали с событийной моделью, или варитесь в каком-то собственном мирке. Что в общем неудивительно, учитывая, какую мизерную долю рынка сейчас занимает C++. Посмотрите по сторонам- долинные корпорации давно всё выложили, только используй.
Здравствуйте, Lexey, Вы писали:
BFE>>Только вот при вызове Button::RemoveOnButtonPress() внутри callback'а скорее всего получится segmentation fault или другое UB: ведь в момент вызова callback'а внутри прохода std::for_each будет удалён объект на который указывает текущий итератор.
L>Это легко обходится через копирование колбэков во временный контейнер и вызов for_each поверх него. Это довольно стандартное решение для ситуаций, когда возможны описки из колбэков.
С простым копированием не так все просто: RemoveOnButtonPress может вызываться не только для удаления текущего обработчика, но и для любого другого. В том числе и для тех обработчиков, до которых внутри for_each-а пока не дошли. Если for_each будет идти по временному контейнеру, то получится, что во временном контейнере останется обработчик, который уже изъят из основного. И будет вызван. Что может сильно удивить пользователя, который этот обработчик только что изъял.
Тут нужна более хитрая схема. Например, с дополнительным флагом valid/invalid для каждой подписки. Если подписка удаляется в момент публикации (т.е. внутри for_each-а), то физически она не удаляется, а флаг для нее меняется на invalid (+ еще взводится отдельный флаг, который показывает, что список подписок изменился). Перед вызовом подписчика проверяется флаг для него. Если valid, то вызывается. Если invalid, то пропускается. После выхода из for_each-а публикации проверяется общий флаг наличия изменений в списке. Если изменения есть, то идет еще один цикл с изъятием всех invalid подписок.
А если добавить сюда еще и возможность вызова AddOnButtonPress в момент публикации, то ситуация становится еще интереснее. И, возможно, использование std::list вместо std::vector в таких условиях более оправдано, не смотря на все недостатки std::list-а.