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++ деструкторы?

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

так и есть. скорость разработки на не managed языках (C, C++) меньшая точно, и проблем создаёт больше.

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

И что дальше? fclose() закрывает файл в любом случае.

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

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

В объяснениях какой-то конторы, почему она перевела свои проекты с C++ на Java.

Этому так же есть нормальное объяснение. Изначально, когда компьютеры были слабыми, особых конкурентов у C++ не было, поэтому на C++ писали чуть ли не все. Тот же SmallTalk, о котором речь шла выше, обеспечивал более высокую продуктивность программиста, но и требовал за это более мощное железо. Что во времена массового распространения 86-х и 286-х оставляло безопасные и мощные языки, вроде SmallTalk-а не у дел.

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

Однако, прошло немного лет, мощности компьютеров выросли в разы, объемы памяти так же и выяснилось, что писать все на C++ уже совсем не обязательно. Вот почему в начале 2000-х от C++ шел массовый отказ и большой отток программистов.

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

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

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

Ты не забыл, что обсуждается RAII и проблема освобождения ресурсов? Так вот ресурс в данном случае - дескриптор открытого файла. Он будет освобожден. И почему ты решил, что сможешь показать пользователю проблему, если у тебя, например, закончилась память, что и вызвало поцесс освобождения ресурсов? Откуда вообще в сценарии взялся пользователь? Без пользователя уже никуда?

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

очень просто. делаю close() файлу. если это деструктор, то про ошибку я не узнаю - будет сохранён не весь файл. если это status code или exception из нормальной функции, то покажу пользователю диалог - «не могу сохранить файл, попробуй-ка, дружок, сохранить его в другое место. ну или просто попробуй посмотреть, может место закончилось. а тем временем твой документ повисит в памяти, только программу не закрывай.»

вопрос: где пользователь будет нецензурно ругаться - с деструктором, или с нормальным close()?

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

Откуда вообще в сценарии взялся пользователь? Без пользователя уже никуда?

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

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

Торвальдс как-то совершенно определенно объяснил почему он предпочитает именно C: глядя на код он видит как этот код будет преобразован в инструкции процессора и его от этого, скажем кратко, штырит) Конечно, C++ с его RAII, исключениями и прочими шаблонами так однозначно в машинный код не переводится и логика работы программы от этого может быть неочевидной, поэтому под критерии Торвальдса не подходит.

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

В контексте какого стандарта/системы? Что такое «закрывает»?

http://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html

The fclose() function shall perform the equivalent of a close() on the file descriptor that is associated with the stream pointed to by stream.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html

If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified. If an I/O error occurred while reading from or writing to the file system during close(), it may return -1 with errno set to [EIO]; if this error is returned, the state of fildes is unspecified.

HP-UX, например, не закрывает fd, если close упал с EINTR:

http://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/close.2.html

[EINTR]
An attempt to close a slow device or connection or file with pending aio requests was interrupted by a signal. The file descriptor still points to an open device or connection or file.

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

очень просто. делаю close() файлу. если это деструктор, то про ошибку я не узнаю - будет сохранён не весь файл.

Хорошо, ты делаешь:

file.close()

Где ты в этом коде увидел деструктор и RAII?

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

Вопрос на засыпку: в каком состоянии находится дескриптор файла после неудачного вызова close()? Каким-нибудь стандартом оговорено что этим дескриптором после такого вызова можно пользоваться, в том числе повторно вызывать close()?

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

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

Код пишется для ЭВМ. Эта ЭВМ может стоять на автоматической межпланетной станции, покинувшей пределы солнечной системы.

Если в ТЗ описан четкий алгоритм реакции на ошибки закрытия файла, то чем тебе может помешать RAII?

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

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

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

Вот поэтому и нужно считать его закрытым с момента вызова fclose().

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

& DarkEld3r. Такой подход хорош в языках, создаваемых одной компанией или человеком вместе со всех инфраструктурой, в т.ч. продиктованным форматом сериализации. Там можно запилить интерфейс Serializable или метод __repr__.

Для C++ такое не пройдёт. Тем более, предлагалось наследоваться ОТ вектора: нечто обратное наследованию от какого-нибудь ISerializable.

Так что free functions (статические методы) для сериализации is the way to go. Так же, как перегрузка операторов ввода-вывода.

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

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

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

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

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

Повторю вопрос: в чем проблема RAII?

особенно в отсутствие finally.

finally - кривой костыль в отсутствие RAII. Почему кривой? Потому что попадая в finally ты не знаешь какие именно ресурсы были выделены и их нужно освобождать, а какие - нет.

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

Вопрос на засыпку: в каком состоянии находится дескриптор файла после неудачного вызова close()?

POSIX говорит, что если close упал с EINTR или EIO, то состояние дескриптора “unspecified”, что значит, что это нужно смотреть в документации конкретной системы. Linux всегда закрывает.

Каким-нибудь стандартом оговорено что этим дескриптором после такого вызова можно пользоваться, в том числе повторно вызывать close()?

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

Такие дела.

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

close можно вызывать с чем угодно

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

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

Ты ерунду какаю-то написал. Там нет слова descriptor вообще, и не может быть, т.к. это описание стандарта крестов, который платформонезависимый. Под Windows же кресты работают? А там нет никаких дескрипторов.

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

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

чем лучше finally - можно кидать исключения, и не париться про terminate(); finally - это всегда код «на месте», с учётом контекста. с деструктором для обработки ошибок нужно париться. а без finally много гемора с вызовом «release resource» кода. юзать RAII «на месте» - более многословная конструкция с локальными классами.

для меня тут нет однозначного победителя, хотя в плюсах мне finally не хватает точно.

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

Анонимус, ты решил устроить вечер глупых вопросов?

Upon successful completion 0 is returned. Otherwise, EOF is returned and errno is set to indicate the error. In either case any further access (including another call to fclose()) to the stream results in undefined behavior.

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

try { } finally { } довольно просто использовать автоматически, одна конструкция на один ресурс. утечек не будет:

resource = aquire();
try {
} finally {
    release(resource);
}

как тут

https://github.com/dzidzitop/ant_modular/blob/master/src/java/afc/ant/modular...

in.close() гарантированно будет вызван, если файл откроется. при этом поток выполнения будет прерван исключением в любом случае, если попытка работать с файлом провалится.

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 1)
Ответ на: комментарий от dzidzitop

try { } finally { } довольно просто использовать автоматически, одна конструкция на один ресурс. утечек не будет:

Это как? 10 вложенных конструкций на 10 ресурсов?

in.close() гарантированно будет вызван, если файл откроется. при этом поток выполнение будет прерван исключением в любом случае, если попытка работать с файлом провалится.

Что будет если in.close() выкинет исключение? Просто процитируй.

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

Дескриптор-то может утечь, не?

in either case any further access (including another call to fclose()) to the stream results in undefined behavior.

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

Это как? 10 вложенных конструкций на 10 ресурсов?

да. меня не напрягает. но это минус по сравнению с RAII.

Что будет если in.close() выкинет исключение? Просто процитируй.

1) программа прекратит работу.

2) пользователь увидит что-то типа:

BUILD FAILED: An I/O error is encountered while loading the manifest of the module 'foo' ('/hello/world/foo/META-INF/MANIFEST.MF')

если бы потребовалось в другом месте проглотить ошибку, то с finally проблем нет. c RAII с выбором поведения всегда есть нюансы, для каждого класса свои.

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 1)
Ответ на: комментарий от dzidzitop

Если ты в finally выкинешь исключение, то оно просто заменит собой то исключение, которое, собственно, и привело к входу в finally. И если у тебя 10 таких вложенных блоков, то пользователь увидит последнее исключение, а не самое первое, с которого всё началось. Чудесно, не правда ли? И ты ещё после этого критикуешь RAII.

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

-_-

FILE — это файловый дескриптор + буфер + мютекс + что-то там ещё. fclose вызывает close над файловым дескриптором, который, как я уже писал, может и не закрыть его. Это и будет утечкой файлового дескриптора. Не?

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

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

я не критикую RAII - его использую постоянно. но у него есть ограничения и нужно с ними как-то жить. finally + RAII для меня бы заменили catch (...) и неудобства от полужёсткого требования на noexcept для деструкторов. но есть только RAII + catch (...), что не идеально, но жить можно.

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 1)
Ответ на: комментарий от anonymous

FILE — это файловый дескриптор + буфер + мютекс + что-то там ещё. fclose вызывает close над файловым дескриптором, который, как я уже писал, может и не закрыть его. Это и будет утечкой файлового дескриптора. Не?

Анонимус, ты смысл последнего предложения по ссылке, до которого ты докопался, понимаешь? Деструкторы не нужны (?) (комментарий)

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

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

C RAII тоже есть выбор, просто код нужно писать чуть иначе. Например, с использованием future. В чем проблема?

я не критикую RAII - его использую постоянно. но у него есть ограничения и нужно с ними как-то жить. finally + RAII для меня бы заменили catch (...) и неудобства от полужёсткого требования на noexcept для деструкторов. но есть только RAII + catch (...), что не идеально, но жить можно.

Ты просто не осознаешь, что finally - это костыль языка, у которого время жизни объектов не определено. И полноценной заменой RAII finally не является. Ты не можешь наоткрывать в объекте класса на java ресурсов и привязать их ко времени жизни этого объекта, ты вынужден за всеми ресурсами следить вручную и не забывать вызывать метод, который будет их освобождать.

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

проблема в том, что когда нет finally, а нужно гарантированно вызвать file.close() и не потерять исключение, внешнее или от самого file.close(), то код становится значительно сложнее, чем acquire(); try {} finally { release(); }

а поскольку я исключения проглатываю в очень специфических случаях, то банально неудобно на плюсах писать такой код. RAII не очень подходит, а finally достаточно хорош.

finally - не замена RAII. это человеческая замена для catch (...). последний ужасно неудобен.

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

проблема в том, что когда нет finally, а нужно гарантированно вызвать file.close() и не потерять исключение, внешнее или от самого file.close(), то код становится значительно сложнее, чем acquire(); try {} finally { release(); }

Вся сложность великолепно прячется за абстракциями. Достаточно просто ОДИН РАЗ написать парочку соответствующих классов: один - для объектов, которые будут собирать возможные ошибки от RAII, а второй - для умных указателей, которые будут использовать объект такого класса для складирования исключений при освобождении ресурсов. Далее в catch(...) ты сможешь подменить любое предыдущее исключение одним из этих новых (а можешь и все их передать наверх).

Collector c;
try {
  SmartPtr<A> a{c, ...};
  SmartPtr<B> b{c, ...};
  ...
} catch(...) {
  c.throw_if_any();
}

C++ просто гораздо гибче и великолепно расширяется собственными средствами.

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

Безусловный COMMIT из деструктора, это, конечно, сильно!

Решение этой проблемы не подскажешь? :-)

Не допускать таких как ты к программированию.

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

Безусловный COMMIT из деструктора, это, конечно, сильно!

Даже если ты сделаешь условный COMMIT из деструктора, решение не станет от этого сильнее :-)

Не допускать таких как ты к программированию.

Это не решит проблему (которой у меня нет, т.к. мне деструкторы не нужны), и не сделает RAII в C++ на деструкторах универсальным и безопасным :-) Смирись :-)

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

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

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

finally - не замена RAII

Это настолько не замена, что в .NET-е появился IDisposable со специальной конструкцией using в C#, а в Java — try-with-resources. Очевидно потому, что finally просто великолепно справлялся с подобными задачами.

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

Ну, у некого dzidzitop, вероятно, и справляется. Правда, почему-то в коде этого самого dzidzitop треш и угар дела расходятся со словами, но ведь это мелочи. Зачем свои слова делами подтверждать, не правда ли?

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

Но dzidzitop сказал в морг, значит в морг только finally, только хардкор, значит только finally.

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

а про треш и угар - репортай баги.

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

а тут, повторюсь, хамить не надо.

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

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