Здравствуйте, lpd, Вы писали:
S>>А вы, наверное, не понимаете, что вместо (skb+1) может быть что угодно. Скажем (skb++). И тогда макрос развернется во что-то вроде
lpd>Никто в здравом уме не напишет (skb++), поскольку это не указатель на члены массива. Аргумент понятен, но надо понимать что пишешь, без этого все равно никак.
ИМХО, в любой нетривиальной программе количество вещей, которые желательно было бы понимать, очень быстро превышает возможности средней руки разработчика. Мои так точно. Поэтому чем больше помощи от компилятора, тем лучше.
lpd>О вкусах не спорят, но мне не нравится что С++17 является законодателем мод(в том чисел в вакансиях),
Интересно, где это C++17 уже является законодателем мод?
lpd>я считаю исключительно за счет эксплуатации успеха классического С++, а не из-за направления развития.
Многие вещи, которые вы тут подвергаете обструкции, появились еще в C++11, а C++17 только сделал C++ лучше. И не будь в свое время C++11, то не понятно, насколько был бы востребован C++ сейчас вообще.
lpd>Если вам так нравится С++17 — ради бога, страдайте и мучайтесь, я же поищу проекты на обычном С++ — у меня и так проблем хватает чтобы еще ломать голову нужен мув или нет, и искать где именно неявно разлочится lock_guard.
Так для lock_guard не нужен ни C++17, ни даже C++11. Этой штукой во всю пользовались еще во времена предшествовавшие C++98. Вы как-то непоследовательны: то для вас C++98 хорош, то вы RAII (включая lock_guard-ы) в топку отправляете...
Здравствуйте, lpd, Вы писали:
lpd>Во-первых, мув-семантика — это не тривиально. Это новый тип с новыми правилами работы с ним, без опыта с которыми будут сложности.
с чем угодно будут проблемы, если не уметь этим пользоваться, если ты не хочешь пользоваться мув семантикой, никто тебя не заставляет это делать, не добавишь ее поддержку в свой класс и он будет просто копироваться, тоже мне проблема
lpd>Во-вторых, RAII это не серебрянная пуля. Полно случаев когда он не описывает сложное владение объектом.
это какие же?
lpd>Может это и ясно, но синтаксис у умных указателей очень громоздкий. И тут начнутся всякие auto, с которыми уже вообще ничего в коде не видно.
Это чем же он громоздкий? Сишные st1->st2.fld3->st4 это значит не громоздко совсем, да?
CK>>сборка мусора може и удобнее но тормознее, цикличесские ссылки дебажатся довольно тривиально lpd>Не уверен что так тривиально они дебажатся всегда.
с помощью ASan довольно тривиально, но вообще это не приходится делать, если правильно проектировать архитектуру, то бишь делать так, чтобы граф зависимостей объектов был ацикличным и направленным (это также неплохо помогает от дедлоков), то что сишечка позволяет иметь кучу циклических ссылок между объектами вовсе не значит что их нужно обязательно создавать и что это есть хорошо
lpd>Я бы предпочел вручную освобождение прописать, хотя если нравится RAII то могу понять.
тут дело не в RAII, а в том, что вручную придется прописывать в нескольких местах, потому что исключения
Явный new/delete или malloc/free в проекте на С++ это чаще всего code smell, нет реально ни одной причины для того, чтобы выделять и освобождать память или создавать и удалять объекты таким способом. Ты так предпочитаешь делать, ок, но для всех остальных в этом нет никакой логики, это просто код с душком. Автор кода просто зачем-то сделал что-то странное, нужно повнимательнее посмотреть на ревью.
lpd>Вроде как никто не мешает тормозящие массовые объекты и самому при сборке мусора удалять(тут я не специалист). Если сборка мусора тормозит, ее можно отключить и перейти на ручную работу с памятью или умные указатели.
там не удаление объектов тормозит, а поиск объектов, которые никто не использует и которые можно удалить
Здравствуйте, chaotic-kotik, Вы писали:
CK>Здравствуйте, lpd, Вы писали:
lpd>>Во-вторых, RAII это не серебрянная пуля. Полно случаев когда он не описывает сложное владение объектом.
CK>это какие же?
Самое простое это неудобные случаи когда время жизни объекта не совпадает со временем жизни переменной.
И например может быть два объекта со счетчиками ссылок, которые нужно удалять вместе, или с более сложной логикой. Или нужно выделить ресурс в середине одной функции, а освободить в середине совсем другой, не связаной напрямую с первой. Я понимаю, что можно исхитриться, но это же неудобно.
Вообще идея связывать время жизни переменной и какие-то операции по освобождению ресурсов довольно сомнительная. Время жизни переменной — это исключительно синтаксическая вещь, а освобождение ресурсов — императивная операция. И писать обертки над функциями только чтобы создать временную переменную, рассчитывая что где-то компилятор ее удалит, это удалять зубы через нос.
lpd>>Может это и ясно, но синтаксис у умных указателей очень громоздкий. И тут начнутся всякие auto, с которыми уже вообще ничего в коде не видно.
CK>Это чем же он громоздкий? Сишные st1->st2.fld3->st4 это значит не громоздко совсем, да?
Ну все эти unique_ptr<Type> по мне очень длинны если их писать по любому поводу, Type * всяко короче.
CK>с помощью ASan довольно тривиально, но вообще это не приходится делать, если правильно проектировать архитектуру, то бишь делать так, чтобы граф зависимостей объектов был ацикличным и направленным (это также неплохо помогает от дедлоков), то что сишечка позволяет иметь кучу циклических ссылок между объектами вовсе не значит что их нужно обязательно создавать и что это есть хорошо
Циклические ссылки могут понадобиться, и не всегда это плохая архитектура. С++ получается ограничивает программиста, или заставляет его думать об освобождении памяти.
lpd>>Я бы предпочел вручную освобождение прописать, хотя если нравится RAII то могу понять.
CK>Явный new/delete или malloc/free в проекте на С++ это чаще всего code smell, нет реально ни одной причины для того, чтобы выделять и освобождать память или создавать и удалять объекты таким способом. Ты так предпочитаешь делать, ок, но для всех остальных в этом нет никакой логики, это просто код с душком.
Я предпочту сборку мусора явному delete/free. Однако городить unique_ptr<>/shared_ptr<> в простых случаях, где не нужен подсчет ссылок, значит делать освобождение памяти неявным без причины, да еще с неудобным синтаксисом. И вот это уже является слепым следованием за фанатиками вроде Майерса.
CK>там не удаление объектов тормозит, а поиск объектов, которые никто не использует и которые можно удалить
Тормозят объекты, выделяемые в большом количестве в цикле или массово. Их и можно удалять вручную, для ускорения сборки мусора. Где-то сборка мусора не подойдет, в таких проектах можно использовать free/delete + умные указатели.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, andyp, Вы писали:
A>Имхо, с if достаточно полезная ошибка, не очень ясно почему именно not equal считается true. А вот свитч — да, хотелось бы, чтобы работало.
Здравствуйте, Шахтер, Вы писали:
PM>>А какая проблема изначально решалась? Я не понял из стартового сообщения.
Ш>Проблема в том, что для использования 3-way comparision нужен тип для записи результатов сравнения. Вот примерно такой.
Ш>
То есть вас по какой-то причине не устраивают константы из стандартной библиотеки, так что вы решили пропатчить ее реализацию, чтобы иметь возможность делать небезопасные неявные приведения к int?
Понятно, что настоящие программисты так не ошибаются, и вам это начем-то реально нужно. Но чем не устраивает менее варварский способ с функцией-переходником типа
CmpResult myFancyOrdering(std::weak_ordering ord)
{
if (ord < 0) return CmpLess;
if (ord == 0) return CmpEqual;
if (ord > 0) return CmpGreater;
}
Здравствуйте, PM, Вы писали:
PM>То есть вас по какой-то причине не устраивают константы из стандартной библиотеки, так что вы решили пропатчить ее реализацию, чтобы иметь возможность делать небезопасные неявные приведения к int?
Оно безопасное.
PM>Понятно, что настоящие программисты так не ошибаются, и вам это начем-то реально нужно.
Сарказм неуместен. У меня долгоживущий проект, в котором используется enum CmpResult и почему-то никаких проблем с безопасностью это не вызывает. Так что проблема безопасности здесь надумана.
PM>Но чем не устраивает менее варварский способ с функцией-переходником типа PM>
PM>CmpResult myFancyOrdering(std::weak_ordering ord)
PM>{
PM> if (ord < 0) return CmpLess;
PM> if (ord == 0) return CmpEqual;
PM> if (ord > 0) return CmpGreater;
PM>}
PM>
Идиотизм. У меня в std::weak_ordering уже лежит переменная с нужным мне значением. Только она приватная. "Небезопасно", а то вдруг я порежусь!
Мне не нужна непрошенная забота о моей безопасности. Особенно такая, которая тупо мешает работать.
lpd>Самое простое это неудобные случаи когда время жизни объекта не совпадает со временем жизни переменной.
это точно также работает и с умными указателями
shared_ptr<Foo> x = ...;
...
x.reset(new Foo());
...
x = y;
...
lpd>И например может быть два объекта со счетчиками ссылок, которые нужно удалять вместе, или с более сложной логикой. Или нужно выделить ресурс в середине одной функции, а освободить в середине совсем другой, не связаной напрямую с первой. Я понимаю, что можно исхитриться, но это же неудобно.
два объекта со счетчиками ссылок которые нужно удалять вместе, ты и на чистом Си не удалишь вместе не нарушив инвариант счетчика ссылок
lpd>Вообще идея связывать время жизни переменной и какие-то операции по освобождению ресурсов довольно сомнительная. Время жизни переменной — это исключительно синтаксическая вещь, а освобождение ресурсов — императивная операция. И писать обертки над функциями только чтобы создать временную переменную, рассчитывая что где-то компилятор ее удалит, это удалять зубы через нос.
как раз наоборот, компилятор не забудет удалить, а вот кое кто предпочитает писать код с утечками, потому что так "проще"
lpd>Циклические ссылки могут понадобиться, и не всегда это плохая архитектура. С++ получается ограничивает программиста, или заставляет его думать об освобождении памяти.
я не говорил что их невозможно реализовать, но как правило это плохая архитектура
lpd>Я предпочту сборку мусора явному delete/free. Однако городить unique_ptr<>/shared_ptr<> в простых случаях, где не нужен подсчет ссылок, значит делать освобождение памяти неявным без причины, да еще с неудобным синтаксисом. И вот это уже является слепым следованием за фанатиками вроде Майерса.
ну вот чуть выше я предложил пример:
auto x = new X();
auto y = new Y(); // new throws exception here
vs
auto x = std::make_unique<X>();
auto y = std::make_unique<Y>();
в первом случае у тебя утечка памяти, потому что если второй new кинет bad_alloc или конструктор Y кинет исключение, объект на который указывает x не будет удален (предпологается что чуть ниже у тебя есть delete x; delete y;, который не выполнится, если будет выброшено исключение). Если ты попробуешь переписать код так, чтобы этого избежать, то получится жуткая каша, с unique_ptr такой проблемы нет
lpd>Тормозят объекты, выделяемые в большом количестве в цикле или массово. Их и можно удалять вручную, для ускорения сборки мусора. Где-то сборка мусора не подойдет, в таких проектах можно использовать free/delete + умные указатели.
— создание объектов в GC языках — очень быстрая операция, удаление тоже (так как у большинства объектов финализаторы пустые), тормозит stop the world фаза сборки мусора, когда GC останавливает все потоки и помечает все достижимые объекты
— free/delete в современных плюсах, как я уже писал, это code smell, попробуй найди хоть одну причину для их использования, кроме личных предпочтений — ничего не получится, т.к. для любого кейса найдется более подходящий и безопасный вариант нежели new/delete или же malloc/free
Здравствуйте, chaotic-kotik, Вы писали:
CK>Здравствуйте, lpd, Вы писали:
lpd>>Вообще идея связывать время жизни переменной и какие-то операции по освобождению ресурсов довольно сомнительная. Время жизни переменной — это исключительно синтаксическая вещь, а освобождение ресурсов — императивная операция. И писать обертки над функциями только чтобы создать временную переменную, рассчитывая что где-то компилятор ее удалит, это удалять зубы через нос.
CK>как раз наоборот, компилятор не забудет удалить, а вот кое кто предпочитает писать код с утечками, потому что так "проще"
Я понимаю, вот совпало, что переменные на стеке компилятор когда-нибудь удаляет, и решили приспособить это дело под освобождение памяти. Это решение явно притянуто за уши, этим мне и не нравится. Ботинок тоже всегда под рукой, и из него вода не выльется. Но чай-то мы пьем из специальных чашек, а не из обуви. Хотя что будет, если авторитетные киноактеры завтра начнут пить из обуви, я не берусь предсказать.
Точно также освобождение памяти или ресурсов, искусственно привязанных к переменной, в ее деструкторе — это хак чистой воды, лишенный всякой логики. Если ты этого не видишь, то мои аргументы будут бесполезны.
CK>ну вот чуть выше я предложил пример: CK>Если ты попробуешь переписать код так, чтобы этого избежать, то получится жуткая каша, с unique_ptr такой проблемы нет
Я это видел, вариант с прямой проверкой результата вызова оператора new или malloc() кашей не считаю. То, что запись auto x = std::make_unique<X>(); более короткая, не значит что она лучше.
CK>- создание объектов в GC языках — очень быстрая операция, удаление тоже (так как у большинства объектов финализаторы пустые), тормозит stop the world фаза сборки мусора, когда GC останавливает все потоки и помечает все достижимые объекты
Если массовые объекты будут удалены вручную, то stop of the world будет быстрее, о чем я и пишу. В тех редких случаях когда этого недостаточно, можно использовать другие способы управления памятью.
CK>- free/delete в современных плюсах, как я уже писал, это code smell, попробуй найди хоть одну причину для их использования, кроме личных предпочтений — ничего не получится, т.к. для любого кейса найдется более подходящий и безопасный вариант нежели new/delete или же malloc/free
Ну вот десятки лет пока умные указатели не встроили в С++, все (в том числе программисты получше Страуструпа и других С++ников) знали про умные указатели, и почти никто ими не пользовался, кроме как когда они реально были нужны для учета ссылок. А как только Майерс с фанатиками начали пропагандировать unique_ptr<>/shared_ptr<>, сразу выяснилось, что обычный free() code smell. В то время как подавляющее большинство программистов пользуются Java/C# с GC и не страдают этой длиннословной фигней, которую нам впаривают создатели современного С++.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
lpd>Я понимаю, вот совпало, что переменные на стеке компилятор когда-нибудь удаляет, и решили приспособить это дело под освобождение памяти. Это решение явно притянуто за уши, этим мне и не нравится.
он не когда-нибудь удаляет, он их удаляет в порядке обратном их созданию, это называется deterministic destruction и прописано в стандарте явным образом
lpd>Точно также освобождение памяти или ресурсов, искусственно привязанных к переменной, в ее деструкторе — это хак чистой воды, лишенный всякой логики. Если ты этого не видишь, то мои аргументы будут бесполезны.
то что мы можем писать свой код в деструкторе, это тоже так совпало и хак чистой воды? если следовать твоей логике, то писать деинициализацию в деструкторе — хак чистой воды, поэтому класс MyFile должен иметь метод destroy, который нужно явно вызывать перед тем как объект будет удален, а в деструкторе ничего делать не надо, не так ли?
lpd>Я это видел, вариант с прямой проверкой результата вызова оператора new или malloc() кашей не считаю. То, что запись auto x = std::make_unique<X>(); более короткая, не значит что она лучше.
дело не в длине записи, вариант с new не возвращает nullptr, он бросает исключение, проверять его придется так:
try {
x = new X();
y = new Y();
catch (bad_alloc const&) {
// что писать здесь?
}
lpd>Если массовые объекты будут удалены вручную, то stop of the world будет быстрее, о чем я и пишу. В тех редких случаях когда этого недостаточно, можно использовать другие способы управления памятью.
во время stop the world фазы объекты не удаляются (то бишь финализаторы не вызываются и память не освобождается), вместо этого GC всего лишь ходит по указателям и находит живые объекты, представь что у тебя массив на миллиард указателей на объекты, GC пройдет по каждому указателю на объект, заглянет в каждый объект и если там есть указатели, пройдет по ним тоже
и чтобы это работало нормально, компилятор в GC языках вставляет барьер после каждой записи в переменную ссылочного типа, что тоже так себе
lpd>Ну вот десятки лет пока умные указатели не встроили в С++, все (в том числе программисты получше Страуструпа и других С++ников) знали про умные указатели, и почти никто ими не пользовался, кроме как когда они реально были нужны для учета ссылок. А как только Майерс с фанатиками начали пропагандировать unique_ptr<>/shared_ptr<>, сразу выяснилось, что обычный free() code smell.
free это code smell потому что если тебе нужен кусок памяти, то есть std::vector<char> например, если нужно создать объект, то зачем тебе кусок неинициализированной памяти и почему бы не воспользоваться new, если дошло до new, то возникает вопрос, зачем там голый указатель, а не unique_ptr.
Здравствуйте, chaotic-kotik, Вы писали:
CK>Здравствуйте, lpd, Вы писали:
CK>то что мы можем писать свой код в деструкторе, это тоже так совпало и хак чистой воды? если следовать твоей логике, то писать деинициализацию в деструкторе — хак чистой воды, поэтому класс MyFile должен иметь метод destroy, который нужно явно вызывать перед тем как объект будет удален, а в деструкторе ничего делать не надо, не так ли?
Деструктор напрямую связан с объектом по логике. А вот объекты-обертки для освобождения ресурсов или для освобождения памяти — это хак.
lpd>>Я это видел, вариант с прямой проверкой результата вызова оператора new или malloc() кашей не считаю. То, что запись auto x = std::make_unique<X>(); более короткая, не значит что она лучше.
CK>дело не в длине записи, вариант с new не возвращает nullptr, он бросает исключение, проверять его придется так:
Обрабатывать исключение от каждого new отдельно. Но вообще выброс исключения new при нехватке памяти вместо возврата ошибки — сама по себе не самая удобная схема, имхо, впрочем вроде как это поведение можно менять.
CK>free это code smell потому что если тебе нужен кусок памяти, то есть std::vector<char> например, если нужно создать объект, то зачем тебе кусок неинициализированной памяти и почему бы не воспользоваться new, если дошло до new, то возникает вопрос, зачем там голый указатель, а не unique_ptr.
unique_ptr<> освобождается неявно и записывается длинно, лично на мой вкус. Аргументы я свои изложил, тут не вижу смысла дальше спорить.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, Шахтер, Вы писали:
Ш>Простой пример: лексикографическое сравнение.
Суть-то ясна, я к тому, что
if( CmpResult ret=Cmp(hash,obj.hash); ret != std::strong_ordering::equal ) return ret;
имхо даже читабельнее, хотя и больше букв. Можно конечно алиас покороче на std::strong_ordering::equal завести. А вот то, что не работает в свитчах — имхо не есть хорошо.
Здравствуйте, lpd, Вы писали:
lpd>Ну вот десятки лет пока умные указатели не встроили в С++, все (в том числе программисты получше Страуструпа и других С++ников) знали про умные указатели, и почти никто ими не пользовался, кроме как когда они реально были нужны для учета ссылок. А как только Майерс с фанатиками начали пропагандировать unique_ptr<>/shared_ptr<>, сразу выяснилось, что обычный free() code smell. В то время как подавляющее большинство программистов пользуются Java/C# с GC и не страдают этой длиннословной фигней, которую нам впаривают создатели современного С++.
У любой сборки мусора есть свои и преимущества и недостатки. Код с нормальным сборщиком мусора (т.е. не stop-the-world) на многоядерной машине просто порвет любой C++ код со своей традиционностью. Но, только в заданных рамках. А после этих рамок будут рандомные фризы и вообще трудно пойми что.
Традиционный способ проигрывает в короткой перспективе, и сильно — но зато масштабируется без больших сюрпризов, при этом не требует сложной машинерии.
И потом, старый код десятилетней давности насквозь утыкан умными указателями, при чем — у всех свои собственные, один кошернее другого. Так что стандартизация в них — это хороший плюс. И все потихоньку еще переходят на них.
Ну, а их бездумное тыкание совсем везде — это едвали имеет отношение к языку и пропаганде. В нормальном C++ коде большая половина кода, имхо, утыкана обычными указателями, ну или их подвидом — ссылками.
Re: Верблюд - это лошадь, разработанная комитетом... :)))
lpd>Циклические ссылки могут понадобиться, и не всегда это плохая архитектура. С++ получается ограничивает программиста, или заставляет его думать об освобождении памяти.
А сишечка, я так понимаю, программиста не ограничивает, и не заставляет думать об освобождении памяти? Ну, ок
Здравствуйте, LaptevVV, Вы писали:
LVV>Была такая шутка в советское время по поводу разработки языков программирования... LVV>Лучшие языки получались у одиночек.
Не только языки. Хочешь угробить дело -- создай комитет.
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, LaptevVV, Вы писали:
LVV>>Была такая шутка в советское время по поводу разработки языков программирования... LVV>>Лучшие языки получались у одиночек.
Ш>Не только языки. Хочешь угробить дело -- создай комитет.
Ну комитет утомил уже давно и не меня одного. У них запор сменился вербальной диареей. Все нововведения размазаны тонким слоем по трём стандартам.
Хех, даже ретрограды в гугле, посчитав, что у них "around 70% of our serious security bugs are memory safety problems", начинают наконец-то что-то подозревать "we feel it may be necessary to ban raw pointers from C++" https://www.chromium.org/Home/chromium-security/memory-safety
Здравствуйте, Voivoid, Вы писали:
V>Хех, даже ретрограды в гугле, посчитав, что у них "around 70% of our serious security bugs are memory safety problems", начинают наконец-то что-то подозревать "we feel it may be necessary to ban raw pointers from C++" V>https://www.chromium.org/Home/chromium-security/memory-safety
35%, половина из memory-related багов — это use after free. Умные указатели от неё не спасают.
Вернее так: спасение от use-after-free это GC и/или подсчёт ссылок, что сильно бьет по производительности c-style copy-free кода.
Собственно в статье об этом и написано, бан голых указателей далеко не первый пункт в предлагаемых решениях.