Re[2]: RAII и исключения в конструкторе
От: C0x  
Дата: 05.07.20 08:37
Оценка:
Здравствуйте, Мирный герцог, Вы писали:

МГ>Здравствуйте, C0x, Вы писали:


C0x>>Привет,


МГ>привет, подобная машинерия лишь усложняет код на ровном месте, и то что автору кажется "удобным" становится головной болью для мэйнтейнеров кода. Как ad-hoc решение используется тайпдеф а std::unique_ptr с кастомным делетером, о чём уже упомянуто выше, или нужно не полениться и написать таки враппер для конкретного типа хендла.



То есть тебе не кажется странным использовать объект с именем unique_ptr для совершенно другой цели — выполнить логику удаления? Это я и называю костылями — использования не по назначению типов. Что касается врапперов над хэндлами все ок,пока логика — просто удалить хэндл, а если чуть сложнее то уже придется городить ещё кучу объектов непонятного назначения.
Re[2]: RAII и исключения в конструкторе
От: std.denis Россия  
Дата: 05.07.20 09:00
Оценка:
σ>Не нужно возиться с конструкторами базовых классов, нужно сделать конструктор с `LoadHeavyResource1` delegating-конструктором
σ>См. https://youtu.be/uQyT-5iWUow?t=3147, How to handle constructors that must acquire multiple resources in an exception safe manner
кмк, по сабжевому вопросу лучше смотреть с 54:30
Re[3]: RAII и исключения в конструкторе
От: PlushBeaver  
Дата: 05.07.20 09:22
Оценка: +5
Здравствуйте, C0x, Вы писали:

PB>>Сложно --- наследование и шаблоны на ровном месте, ненадежно --- можно забыть освободить ресурс или освободить не в том порядке. Пусть каждый ресурс будет отдельным объектом с RAII в составе A.


C0x>Мне вот это почему-то тоже кажется сложным. У меня есть типы типа HANDLE, оборачивать их в спец объект ради одной простой цели — надежного уничтожения везде и всегда кажется черезчурным.


Три даже не класса, а typedef'а для unique_ptr, каждый из которых делает одну простую вещь, сложнее, чем один класс, который в конструкторе и деструкторе жонглирует тремя хэндлами? Бонусом смартпоинтеры запретят копирование A, но разрешает его перемещение.

C0x>Да и хочется не с врапперами в коде работать а с исходными типами (видить их в полях класса и возращаемых зачениях функций).


А почему? Например, по HANDLE нельзя сказать, мы владеем этим объектом или нам его дали откуда-то и уничтожат вовне, а по Resource vs const Resource& или Resource vs HANDLE это видно, если не использовать голые хэндлы и указатели как владеющие (что сейчас рекомендуемая практика, кроме Qt). Насчет draw(HANDLE brush, HANDLE dc) против draw(const Brush& brush, const DC& dc) можно поспорить, что скрывается сущность ресурсов, но на мой взгляд, читаемость выше, а за точными типами пусть компилятор следит.

C0x>Смартпоинтеры на мой личный взгляд это в целом костыль, который превращает код в лапшу.


"Лапша" в данном случае в том, что вместо ApiFunc(resource1) придется писать ApiFunc(resource1.get()). Но это как раз и хорошо, что нельзя отдать куда-то хэндл и не подумать о владении им. Смартпоинтеры не просто автоматически освобождают ресурс, они еще и делают логику использующего их кода проще (не надо описывать освобождение, копирование, перемещение) и безопаснее (заставяют думать о владении).
Re[5]: RAII и исключения в конструкторе
От: velkin Удмуртия https://kisa.biz
Дата: 05.07.20 09:46
Оценка:
Здравствуйте, C0x, Вы писали:

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


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

Я даже читал как-то такую отмазу, что это не Java такая тормознутая, это повёрнутые на абстракциях программисты сделали из неё тормознутую. А если вроде как писать в другом стиле, то всё будет не так уж и плохо.

C++ традиционно считается быстрым, но так ли это? А дело то не в том, что он быстрый сам по себе, а в том, что программисты всё же стараются выбирать наиболее быстрые решения.

Когда программисты говорят, а вот у нас есть в языке такая то особая функция, а вот у вас её нет. Так без проблем, эти функции можно создать самим, если уж так надо.

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

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

Вот тот же механизм исключений в C++, если вдуматься это высокоуровневая абстракция. Её можно использовать, если нужны исключения, вопрос в том, можно ли обойтись без исключений. Это всё не так однозначно, а к примеру, в .NET я бы по аналогии напихал их везде и даже не стал бы думать над такими вопросами.
Re: RAII и исключения в конструкторе
От: kov_serg Россия  
Дата: 05.07.20 10:31
Оценка:
Здравствуйте, C0x, Вы писали:

C0x>Надоели всякие Begin, End, Open, Close методы в программах. Хочу придерживаться принципа RAII.

А почему он вас так привлекает? Или только потому что миллионы мух не ошибаются?

Гораздо логичнее что бы за все ресурсы, которые использует объект, отвечал не он, а тот кто заставил его работать.
Так в любой момент можно его пристрелить остановить и не торопясь освобождать то что он использовал, не заботясь о том в каком состоянии он умер.
Более того сразу можно смотреть что он использовал, сколько и ограничивать ресурсы по ходу выполнения если необходимо.
Re[3]: RAII и исключения в конструкторе
От: _NN_ www.nemerleweb.com
Дата: 05.07.20 11:34
Оценка:
Здравствуйте, C0x, Вы писали:

C0x>То есть тебе не кажется странным использовать объект с именем unique_ptr для совершенно другой цели — выполнить логику удаления? Это я и называю костылями — использования не по назначению типов. Что касается врапперов над хэндлами все ок,пока логика — просто удалить хэндл, а если чуть сложнее то уже придется городить ещё кучу объектов непонятного назначения.


А зачем тогда у unique_ptr, shared_ptr есть такая возможность если не для этого

Всё уже сделано за нас (касательно Windows): https://github.com/Microsoft/wil/wiki/RAII-resource-wrappers
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: RAII и исключения в конструкторе
От: wander  
Дата: 05.07.20 22:43
Оценка: +1
Здравствуйте, C0x, Вы писали:

C0x>Попробую объяснить свою думку. Мне использование спец. объектов (те же смартпоинтеры) для уничтожения кажется большим костылем. И такие костыли вызывают у программистов на Си#/Java насмешки типа "Да у вас там в Си++ всё на костылях и костылями погоняете".


Хочу, говорит, RAII использовать. А потом заявляет, что это костыль. Занятно.

А вообще, все эти высказывания про костыли, они ведь от непонимания. Или от поверхностного понимания, что еще хуже.
Re[4]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:16
Оценка:
Здравствуйте, a7d3, Вы писали:

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


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


B>>>Но обычно в таком случае делается класс-обертка для конкретного типа ресурсов. Тогда весь код выглядит так:


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


A>А какая разница вызывается эта сложная логика после того как освобождаемый ресурс стал не нужен или же в случае раскрутки стека из-за исключения?


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

A>Просто не забывать про SOLID и делать классы максимально простыми — первая же буква S.


В моем случае SOLID то же вроде как не нарушается. У меня есть 1 базовый класс, делающий только одно — Release данных которые собственно сам же и представляет.
Re[4]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:31
Оценка:
Здравствуйте, PlushBeaver, Вы писали:

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


PB>>>Сложно --- наследование и шаблоны на ровном месте, ненадежно --- можно забыть освободить ресурс или освободить не в том порядке. Пусть каждый ресурс будет отдельным объектом с RAII в составе A.


C0x>>Мне вот это почему-то тоже кажется сложным. У меня есть типы типа HANDLE, оборачивать их в спец объект ради одной простой цели — надежного уничтожения везде и всегда кажется черезчурным.


PB>Три даже не класса, а typedef'а для unique_ptr, каждый из которых делает одну простую вещь, сложнее, чем один класс, который в конструкторе и деструкторе жонглирует тремя хэндлами? Бонусом смартпоинтеры запретят копирование A, но разрешает его перемещение.


Конструктор и деструктор изначально для этого и нужны в Си++ у каждого объекта, чтобы его данные можно было подчищать. То что программисты ленивые и придумывают костыли, чтобы не забыть что-то удалить, это нормально, но это костыли порожденные пороком

C0x>>Да и хочется не с врапперами в коде работать а с исходными типами (видить их в полях класса и возращаемых зачениях функций).


PB>А почему? Например, по HANDLE нельзя сказать, мы владеем этим объектом или нам его дали откуда-то и уничтожат вовне, а по Resource vs const Resource& или Resource vs HANDLE это видно, если не использовать голые хэндлы и указатели как владеющие (что сейчас рекомендуемая практика, кроме Qt). Насчет draw(HANDLE brush, HANDLE dc) против draw(const Brush& brush, const DC& dc) можно поспорить, что скрывается сущность ресурсов, но на мой взгляд, читаемость выше, а за точными типами пусть компилятор следит.



Ну например хотя бы потому, что код работающий с Хэндлами легко найти на Github, а если его завернуть во Wrapper то на Гитхаб будет помойка из разнородного кода, который вроде бы делает одно и то же но при этом выглядит совершенно по разному.


C0x>>Смартпоинтеры на мой личный взгляд это в целом костыль, который превращает код в лапшу.


PB>"Лапша" в данном случае в том, что вместо ApiFunc(resource1) придется писать ApiFunc(resource1.get()). Но это как раз и хорошо, что нельзя отдать куда-то хэндл и не подумать о владении им.


Нет не хорошо, потому-что нужно придерживаться принципа KISS и YAGNI, иначе мы будем думать о многом, а в итоге нам нужно просто вызвать API функции и передать туда тупа Хэндл.
Re[6]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:39
Оценка:
Здравствуйте, velkin, Вы писали:

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


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


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


Нет, я видимо не правильно объяснил. Я стараюсь в логике алгоритмов не использовать указателей, а только стэковые объекты и ссылки на них. Передача объектов по ссылке по скорости то же самое или даже быстрее чем по указателю. New и Delete я конечно же буду использовать там где мне нужно выделять болшие массивы данных, например передавать картинки или звуковые потоки. Но эти данные будут завернуты внутри простых объектов у которых будет просто ссылка на эти данные и естественно деструктор который их почистит (либо vector<BYTE>).

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


На то мы и программисты, чтобы делать то что нам нравится. Другое дело, что это не всегда можно пустить в Продакшен. Вот мне лично нравится жонглировать Шаблонами, я люблю в Си++ по максимуму использовать Шаблоны, кому-то это покажется сложным или тормозным и т.д. и т.п., но я лично считаю что Шаблоны например одно из самых крутых фич языка Си++.


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


V>Вот тот же механизм исключений в C++, если вдуматься это высокоуровневая абстракция. Её можно использовать, если нужны исключения, вопрос в том, можно ли обойтись без исключений. Это всё не так однозначно, а к примеру, в .NET я бы по аналогии напихал их везде и даже не стал бы думать над такими вопросами.


Я начал писать свою библиотеку и старался опираться везде на коды ошибок. Потом столкнулся с проблемой что эти коды в 99% нужно переводить в строковое описание. В итоге пришел к тому, что проще кидать исключения со строками чем городить кучу не нужного кода.
Re[4]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:43
Оценка:
Здравствуйте, a7d3, Вы писали:

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


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


TB>>>Каждая пара LoadHeavyResource1()-ReleaseHeavyResource1 должна быть в отдельном объекте.

TB>>>Один объект — один ресурс.

C0x>>Попробую объяснить свою думку. Мне использование спец. объектов (те же смартпоинтеры) для уничтожения кажется большим костылем. И такие костыли вызывают у программистов на Си#/Java насмешки типа "Да у вас там в Си++ всё на костылях и костылями погоняете". А вот моё решении, на мой опять же взгляд, более похоже на четкий паттерн для решения задачи освобождения ресурсов заданного класса на базе языковой конструкции и порядка вызова деструкторов. И вот это мне кажется более аккуратным способом, чем тот же "костыль" IDisposable в C# для управления освобождением ресурсов.


A>Базовые классы и наследование от них — это инструмент взаимозаменяемости.


Поклонники ООП считают что это их инструмент, а я не поклонник и смотрю на это просто как на инструмент Языка.

A>по канонам ООП должно делаться через агрегированием с делегированием внешних вызовов.


Си++ не был бы Си++ если бы не был мультипарадигменным языком, поэтому Каноны ООП это лишь каноны ООП.
Re[4]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:49
Оценка:
Здравствуйте, wander, Вы писали:

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


C0x>>Попробую объяснить свою думку. Мне использование спец. объектов (те же смартпоинтеры) для уничтожения кажется большим костылем. И такие костыли вызывают у программистов на Си#/Java насмешки типа "Да у вас там в Си++ всё на костылях и костылями погоняете".


W>Хочу, говорит, RAII использовать. А потом заявляет, что это костыль. Занятно.


Смартпоинтер и RAII это одно и тоже?

W>А вообще, все эти высказывания про костыли, они ведь от непонимания. Или от поверхностного понимания, что еще хуже.


Естественно, за любым костылем лежит целая история причинно-следственных связей. Ну вот к примеру взять Смартпоинтер. Любой программист на языке с GC скажет что это очевидно костыль, просто потому-что у вас ребята нет GC, но вы пытаетесь обойти этот недостаток пихая во все щели свои смартпоинтеры. Программист на Си++99 смотря на смартпоинтер скажет что это костыль, потому-что вы лентяи и не можете аккуратно писать код и следить за указателями и хэндлами.
Re[2]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 07:52
Оценка:
Здравствуйте, σ, Вы писали:

σ>Не нужно возиться с конструкторами базовых классов, нужно сделать конструктор с `LoadHeavyResource1` delegating-конструктором

σ>См. https://youtu.be/uQyT-5iWUow?t=3147, How to handle constructors that must acquire multiple resources in an exception safe manner

WOW. Не знал, спасибо. Это видимо то что нужно!
Re[5]: RAII и исключения в конструкторе
От: a7d3  
Дата: 06.07.20 07:53
Оценка:
Здравствуйте, C0x, Вы писали:

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


A>>по канонам ООП должно делаться через агрегированием с делегированием внешних вызовов.


C0x>Си++ не был бы Си++ если бы не был мультипарадигменным языком, поэтому Каноны ООП это лишь каноны ООП.


И всего их две штуки — процедурная и ОО. Потому и выбор между — либо крестик снять, либо трусы надеть.
Это идиом с подходами в С++ много, но они все в рамках или процедурного (модульного) программирования или же ООП.
Так что или соблюдаешь ООП или идёшь дальше клянчить или выдумывать свои паттерны.
Re[6]: RAII и исключения в конструкторе
От: C0x  
Дата: 06.07.20 08:00
Оценка:
Здравствуйте, a7d3, Вы писали:

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


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


A>>>по канонам ООП должно делаться через агрегированием с делегированием внешних вызовов.


C0x>>Си++ не был бы Си++ если бы не был мультипарадигменным языком, поэтому Каноны ООП это лишь каноны ООП.


A>И всего их две штуки — процедурная и ОО. Потому и выбор между — либо крестик снять, либо трусы надеть.

A>Это идиом с подходами в С++ много, но они все в рамках или процедурного (модульного) программирования или же ООП.
A>Так что или соблюдаешь ООП или идёшь дальше клянчить или выдумывать свои паттерны.

А вот тут ты не прав. Есть ещё шаблоны и стат.программирование, ни с процедурами ни с ООП они ничего общего не имеют и дают совершенно интересные решения по сравнению с классическим ООП.
Re[3]: RAII и исключения в конструкторе
От: AlexGin Беларусь  
Дата: 06.07.20 08:02
Оценка:
Здравствуйте, C0x, Вы писали:
...
C0x>Смартпоинтеры на мой личный взгляд это в целом костыль, который превращает код в лапшу.


Нужно только разобраться со смартпоинтерами — и Ваше мнение о них изменится! Они станут Вашими друзьями.
На самом деле — это очень толковая штука, решающая многие проблемы, и прежде всего — высвобождения ресурсов.
Re[5]: RAII и исключения в конструкторе
От: a7d3  
Дата: 06.07.20 08:08
Оценка:
Здравствуйте, C0x, Вы писали:

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



A>>А какая разница вызывается эта сложная логика после того как освобождаемый ресурс стал не нужен или же в случае раскрутки стека из-за исключения?


C0x>Меня интересует только второй случай, потому-что ресурс в любом случае станет не нужен как-только объект содержащий его будет уничтожен. У меня ресурсы не шарятся между объектами.


A>>Просто не забывать про SOLID и делать классы максимально простыми — первая же буква S.


C0x>В моем случае SOLID то же вроде как не нарушается. У меня есть 1 базовый класс, делающий только одно — Release данных которые собственно сам же и представляет.


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

Сначала надо было уйти от классов управляющих множеством ресурсов напрямую. Если есть минимально возможные обёртки над ресурсами, каждым типом в отдельности, то это следование SRP.
А вот пихать эти классы-обёртки в качестве базовых, строя иерархию сугубо ради повторного использования кода — это нарушение LSP.
Re[5]: RAII и исключения в конструкторе
От: AlexGin Беларусь  
Дата: 06.07.20 08:10
Оценка:
Здравствуйте, C0x, Вы писали:
...
C0x>Нет не хорошо, потому-что нужно придерживаться принципа KISS и YAGNI, иначе мы будем думать о многом, а в итоге нам нужно просто вызвать API функции и передать туда тупа Хэндл.


ИМХО повседневная практика разработки софта — это как раз компромисс между минимальщиной (KISS & YAGNI) и реальной оценкой требований Заказчика.
И если есть надёжный и полезный для практики C++ инструмент, такой как смарт-поинтеры, то как раз отказ от его применения и есть ошибка
Re[7]: RAII и исключения в конструкторе
От: so5team https://stiffstream.com
Дата: 06.07.20 08:11
Оценка:
Здравствуйте, C0x, Вы писали:

C0x>Я стараюсь в логике алгоритмов не использовать указателей, а только стэковые объекты и ссылки на них. Передача объектов по ссылке по скорости то же самое или даже быстрее чем по указателю.


Можно пример кода, в котором передача указателя на стековый объект куда-то была бы медленнее, чем передача ссылки на такой же стековый объект?
Re[7]: RAII и исключения в конструкторе
От: a7d3  
Дата: 06.07.20 08:19
Оценка:
Здравствуйте, C0x, Вы писали:

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


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


A>>И всего их две штуки — процедурная и ОО. Потому и выбор между — либо крестик снять, либо трусы надеть.

A>>Это идиом с подходами в С++ много, но они все в рамках или процедурного (модульного) программирования или же ООП.
A>>Так что или соблюдаешь ООП или идёшь дальше клянчить или выдумывать свои паттерны.

C0x>А вот тут ты не прав. Есть ещё шаблоны и стат.программирование, ни с процедурами ни с ООП они ничего общего не имеют и дают совершенно интересные решения по сравнению с классическим ООП.


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

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

Для примера, в данном случае, в этом треде достаточно знать про делегирование конструкторов и вопрос решается — освоением средств языка.
А можно и лучше через SRP SOLID — каждому типу сделать свой класс отвечающий за стратегию захвата и освобождения. Тогда класс использующий эти ресурсы, будет отвечать лишь за порядок захвата (выделения) и освобождения.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.