LINUX.ORG.RU

Деструкторы не нужны (?)

 


0

5

Тут в соседней теме один анон сказанул следующее:

Дело не в том. Сишка, она про написание руками + можно навесит абстракций, аки глиб/гобджект. Кресты же — изначально нагромождение абстракций со строками, срущими в кучу, функциональными объектами, методами, вызывающимися неявно (например, деструкторы, на которые жаловался кармак) и проч

Собственно, хотелось бы поговорить о выделенном.

Антон прикрылся ссылкой, по которой про деструкторы я так ничего и не нашёл. Более того, в твиттере Кармака всё выглядит с точностью до наоборот — https://twitter.com/id_aa_carmack/status/172340532419375104

RAII constructor / destructor pairing and templates for type safe collections are pretty high on my list of C++ benefits over C

Кто прав? Кто виноват? И нужны ли в итоге C++ деструкторы?

Ответ на: комментарий от utf8nowhere

stl не позволяет наследоваться от вектора

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

mythCreator
()
Ответ на: комментарий от Deleted

что будет если деструктор при закрытии файлового дескриптора сделает flush buffer, а запись на диск окончится неудачей?

деструкторы не дружат с исключениями и обработкой ошибок. их большой минус.

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

деструкторы не дружат с исключениями и обработкой ошибок. их большой минус.

А что дружит?

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

А что будет, если это сделает обычная функция?

В отличии от обычной функции, деструктор не может сообщить о неудаче нормальным способом - ни исключением, ни кодом :-) Отсюда следует, что кроме как освободить память на localhost, даже написать письмо Страуструпу с приветом из деструктора надёжно нельзя - может быть неудача :-) Да что там письмо, даже запись в каком-либо логе может так и не появиться :-)

anonymous
()
Ответ на: комментарий от anonymous

А что будет, если это сделает обычная функция?

В отличии от обычной функции [...]

Я не об этом спрашивал.

Да что там письмо, даже запись в каком-либо логе может так и не появиться :-)

Неужели на вызов syslog тоже накладываются какие-то ограничения?

tailgunner ★★★★★
()
cleanup (cleanup_function)
    The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored.

    If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally. 

gcc для C тоже умеет в RAII.

DELIRIUM ☆☆☆☆☆
()
Ответ на: комментарий от monk

Можно было и определить порядок.

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

Ну и плюс цепочки исключений сложнее правильно обрабатывать. Так-то имеется std::nested_exception, но особой популярностью не пользуется.

DarkEld3r ★★★★★
()
Ответ на: комментарий от tailgunner

Неужели на вызов syslog тоже накладываются какие-то ограничения?

Да, вызов syslog - это ещё одно надёжное применение деструкторов кроме освобождение памяти на localhost :-) Кстати, syslog нет стандарте C++, он есть в POSIX :-)

anonymous
()
Ответ на: комментарий от monk

Тогда про логированиие должен знать сам деструктор.

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

Вопрос не по теме: можно ли тебе дурацкие вопросы про Racket позадавать? Через какой-нибудь гиттер/скайп/что-то ещё.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Да, реализации обычно предлагают возможность «отключить исключения», но если мне не изменяет память, в стандарте такого нет.

Потому что в стандарте есть стандартная библиотека с исключениями :-)

В общем, от С++ не этого ждут.

А чего ждут от C++? :-)

anonymous
()
Ответ на: комментарий от monk

А в C++ можно добавить метод serialize() не наследуясь?

Метод - нет, но такие штуки в С++ принято делать другим способом. А именно добавлять специализацию шаблона, примерно как с std::hash сделано. Правда с приватными данными облом будет.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Вопрос не по теме: можно ли тебе дурацкие вопросы про Racket позадавать?

Мелочь, а приятно :-)

anonymous
()
Ответ на: комментарий от DELIRIUM

gcc для C тоже умеет в RAII.

Это скорее finally-блок, чем RAII.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Да

Ясно. Улыбчивый дурачок верен себе.

Уважаемый старожил :-) Рассмотрите ещё раз то, что было сказано:

Да, вызов syslog - это ещё одно надёжное применение деструкторов кроме освобождение памяти на localhost :-)

anonymous
()
Ответ на: комментарий от tailgunner

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

dzidzitop ★★
()
Ответ на: комментарий от utf8nowhere

Ну int естественно исключение, это косяк, да. Но кол-во простых типов можно по пальцам двух рук пересчитать (если с signed/unsigned) и они всем известны. При этом когда ты пишешь новый класс тебе достаточно у него реализовать интерфейсный метод для сериализации и все. Как в c#. При этом не прибегать к свободным функциям, я бы их вообще старался избегать без крайней необходимости.

Dudraug ★★★★★
()
Ответ на: комментарий от dzidzitop

а файлы закрывать или любые другие действия делать, где может возникнуть runtime ошибка, в деструкторе нельзя.

От это вы ща прям мощно задвинули, внушаить. Обосновать сможете?

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Потому что в стандарте есть стандартная библиотека с исключениями :-)

И что? Если исключить bad_alloc, про который разговор отдельный, то все остальные исключения можно не использовать.

DarkEld3r ★★★★★
()
Ответ на: комментарий от utf8nowhere

Наследование не даст доступа к private.

Да, я ерунду сказал. Тем не менее, причина иметь сериализацию в самом классе всё-таки есть.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

И что? Если исключить bad_alloc, про который разговор отдельный, то все остальные исключения можно не использовать.

Что значит «можно не использовать»? :-) Покажи, как избежать/не использовать std::regex_error :-) Или это тоже отдельный разговор? :-)

anonymous
()
Ответ на: комментарий от anonymous

Что будете делать, если close вернул ошибку?

А что вы будете делать, если у вас есть вектор с N открытыми файлами, вы последовательно начали дергать close для них и на i-ом файле получили ошибку?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

i-ом файле получили ошибку

Ну так я буду знать, что у меня ошибка. Могу программу завершить, могу еще раз попробовать.

А в деструкторе что предлагаете, вызывать exit? Или может быть пробовать закрывать дескриптор снова и снова из деструктора?

anonymous
()
Ответ на: комментарий от anonymous

Ну так я буду знать, что у меня ошибка. Могу программу завершить, могу еще раз попробовать.

Ну знаете вы, что у вас ошибка на закрытии i-го файла и что? Как вы в коде выразите это знание? Что вы с оставшимися файлами будете делать?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Как вы в коде выразите это знание?

Могу программу завершить, могу еще раз попробовать.

anonymous
()
Ответ на: комментарий от eao197

Ну и в догонку:

Not checking the return value of close() is a common but nevertheless serious programming error. It is quite possible that errors on a previous write(2) operation are first reported at the final close(). Not checking the return value when closing the file may lead to silent loss of data. This can especially be observed with NFS and with disk quota.

anonymous
()
Ответ на: комментарий от dzidzitop

что будет если деструктор при закрытии файлового дескриптора сделает flush buffer, а запись на диск окончится неудачей?

А что будет, если это сделает обычная функция?

что захочет, то и сделает

Я так понимаю, конкретики не будет.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Not checking the return value of close() is a common but nevertheless serious programming error

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

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Покажи, как избежать/не использовать std::regex_error :-)

Не использовать <regex>. (:

Ну да, подловил, про регекспы я совсем забыл. Может ещё что найдётся?

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

Могу программу завершить, могу еще раз попробовать.

Вы издеваетесь?

Вот у вас программа, скажем, MQ-шный брокер или СУБД. В ней открыто N файлов. Программа получает сигнал на завершение своей работы. Например, перед перезагрузкой ОС.

Вам нужно закрыть эти N файлов. На i-ом файле вы получаете ошибку.

Вы прервете программу без закрытия оставшихся файлов? Будете пробовать закрыть еще и еще раз натыкаясь на одни и те же грабли?

eao197 ★★★★★
()
Ответ на: комментарий от DarkEld3r

Ну да, подловил, про регекспы я совсем забыл. Может ещё что найдётся?

Ещё есть std::bad_weak_ptr :-) А ещё те же <thread> и std::async генерят std::system_error направо/налево :-) А ещё std::locale :-)

anonymous
()

да всё очень просто

С++-хейтеры просто врут. У них руки настолько из жопы растут, что они не могут понять как работает деструктор. Поэтому просто приписали Кармаку свой собственный вайн.

i36_zubov
()
Ответ на: комментарий от eao197

Вот у вас программа, скажем, MQ-шный брокер или СУБД.

Вы тут вот шлангуете в своем обычном стиле, но так на вопросы и не ответили.

Вот у вас дескриптор при закрытии в деструкторе выкинул ошибку или исключение, что делать будете? Обрабатывать ошибку в деструкторе?

anonymous
()

Интересная дискуссия про close()

Особенно интересно это в том плане, что у С++-хейтеров файлы надо закрывать вообще руками потому что GC этого не умеет делать.

А самое интересно, что flush никто делать не запрещает до закрытия файла. Но С++ хейтеры из принципа не способны писать программы не через жопу: им же в принципе непонятно, что если данные критичны, такие ситуации надо предусмотреть ЗАРАНЕЕ, до того как они с завываниями и ужимками набросятся на клавиатуру. Например писать во временный файл а потом переименовать(как это делает опеноффис или QSaveFile). Или заранее выделить место на диске и mmapнуть данные в память.

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

i36_zubov
()
Ответ на: комментарий от anonymous

Вот у вас дескриптор при закрытии в деструкторе выкинул ошибку или исключение, что делать будете?

Оберну в try-catch(...).

Теперь ваша очередь. Вы что будете делать? Продолжать изображать из себя идиота?

eao197 ★★★★★
()
Ответ на: Интересная дискуссия про close() от i36_zubov

Особенно интересно это в том плане, что у С++-хейтеров файлы надо закрывать вообще руками потому что

Потому что RAII на деструкторах C++ дальше чем для освобождения памяти на localhost или для записи в syslog ненадёжен :-)

anonymous
()
Ответ на: комментарий от anonymous

Обрабатывать ошибку в деструкторе?

Почему нет?

Dudraug ★★★★★
()
Ответ на: комментарий от anonymous

Потому что RAII на деструкторах C++ дальше чем для освобождения памяти на localhost или для записи в syslog ненадёжен :-)

Чем?

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Чем?

Тем что контроль выполнения неявно передаётся деструктору, а контекст, от которого может зависеть альтернативный сценарий восстановления, - нет :-)

anonymous
()
Ответ на: комментарий от anonymous

Ну так я буду знать, что у меня ошибка. Могу программу завершить, могу еще раз попробовать.

Что мешает это сделать деструкторе? RAII можно на разные уровни двигать, написал класс контроллер для i-файлов, в его деструкторе дергаешь close явно и обрабатываешь ошибки если надо. Извне юзаешь этот свой контроллер, в чем проблема?

А если очень надо обработать ошибку, то можно у класса и явно дернуть close. RAII как и любой другой принцип - лишь пожелание/рекомендация, слепое и фанатичное использование некого принципа/шаблона делает из вас обезьянокодера, а не инженера.

Dudraug ★★★★★
()
Ответ на: комментарий от anonymous

Тем что контроль выполнения неявно передаётся деструктору, а контекст, от которого может зависеть альтернативный сценарий восстановления, - нет :-)

Смотри ниже. Если очень надо, то дергай close явно, если нет, то полагайся на деструктор. Зачем слепо следовать принципу?

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Смотри ниже. Если очень надо, то дергай close явно, если нет, то полагайся на деструктор. Зачем слепо следовать принципу?

Тебе же сказано было, что RAII на деструкторах подходит для освобождения памяти, да для записи в syslog :-) Зачем ты слепо стал переспрашивать, если сам же знаешь ответ :-)

anonymous
()
Ответ на: комментарий от Dudraug

Зачем слепо следовать принципу?

Затем, что на LOR-е нужно набросить очередную лопату на C++, рассказать, что исключения в C++ — говно, в отличии от продолжений в Common Lisp-е. И все это из-за того, что за Common Lisp улыбчивым анонимам не платят, вот и приходится жрать кактус, облегчая себе душевные страдания в каждом топике про C++.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

он вообще предназначен для освобождения ресурсов. т.е. поступила команда «освободить безусловно» и надо её выполнить.

неужели так сложно понять, что файл - это ненадежное хранилище? как и udp и даже tcp сокет - ненадежны. Надо убедиться что все данные приняты/сохранены прежде чем их закрывать.

хотя о чём я. это же программисты на жабе.

i36_zubov
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.