четверг, 16 января 2014 г.

Коротко. "Нелюбителям" FreeAndNil

По мотивам - http://programmingmindstream.blogspot.ru/2013/12/blog-post_3160.html

Что хочу сказать?

Одну ПРОСТУЮ ВЕЩЬ. Стоит ЛИШЬ посмотреть НОВЫЕ исходники от Embarcadero.

В частности FM.

Чтобы увидеть, что FreeAndNil - там ИСПОЛЬЗУЕТСЯ ПОВСЕМЕСТНО.

По-моему это - не "просто так".

По крайней мере это - "согласуется с МОИМ ЛИЧНЫМ ПРАКТИЧЕСКИМ опытом".



Вот "небольшой список" файлов:

V:\Embarcadero\Delphi\fmx\FMX.Ani.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.D2D.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.GDIP.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.GPU.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.GPU.Helpers.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.Canvas.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Colors.pas
V:\Embarcadero\Delphi\fmx\FMX.Context.DX9.pas
V:\Embarcadero\Delphi\fmx\FMX.Context.GLES.pas
V:\Embarcadero\Delphi\fmx\FMX.Context.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Controls.pas
V:\Embarcadero\Delphi\fmx\FMX.Controls3D.pas
V:\Embarcadero\Delphi\fmx\FMX.Dialogs.pas
V:\Embarcadero\Delphi\fmx\FMX.Dialogs.Default.pas
V:\Embarcadero\Delphi\fmx\FMX.Edit.pas
V:\Embarcadero\Delphi\fmx\FMX.Effects.pas
V:\Embarcadero\Delphi\fmx\FMX.ExtCtrls.pas
V:\Embarcadero\Delphi\fmx\FMX.Filter.pas
V:\Embarcadero\Delphi\fmx\FMX.Filter.Effects.pas
V:\Embarcadero\Delphi\fmx\FMX.FontGlyphs.pas
V:\Embarcadero\Delphi\fmx\FMX.Forms.pas
V:\Embarcadero\Delphi\fmx\FMX.Forms.Border.pas
V:\Embarcadero\Delphi\fmx\FMX.Forms.Border.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Forms.Border.Win.pas
V:\Embarcadero\Delphi\fmx\FMX.Forms3D.pas
V:\Embarcadero\Delphi\fmx\FMX.Gestures.pas
V:\Embarcadero\Delphi\fmx\FMX.Gestures.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.Gestures.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Gestures.Win.pas
V:\Embarcadero\Delphi\fmx\FMX.Grid.pas
V:\Embarcadero\Delphi\fmx\FMX.Import.pas
V:\Embarcadero\Delphi\fmx\FMX.InertialMovement.pas
V:\Embarcadero\Delphi\fmx\FMX.Layers3D.pas
V:\Embarcadero\Delphi\fmx\FMX.Layouts.pas
V:\Embarcadero\Delphi\fmx\FMX.ListBox.pas
V:\Embarcadero\Delphi\fmx\FMX.ListView.pas
V:\Embarcadero\Delphi\fmx\FMX.ListView.Types.pas
V:\Embarcadero\Delphi\fmx\FMX.MagnifierGlass.pas
V:\Embarcadero\Delphi\fmx\FMX.Materials.Canvas.pas
V:\Embarcadero\Delphi\fmx\FMX.MaterialSources.pas
V:\Embarcadero\Delphi\fmx\FMX.Media.pas
V:\Embarcadero\Delphi\fmx\FMX.Media.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Media.Win.pas
V:\Embarcadero\Delphi\fmx\FMX.MediaLibrary.Actions.pas
V:\Embarcadero\Delphi\fmx\FMX.Memo.pas
V:\Embarcadero\Delphi\fmx\FMX.Menus.pas
V:\Embarcadero\Delphi\fmx\FMX.Messages.pas
V:\Embarcadero\Delphi\fmx\FMX.Objects.pas
V:\Embarcadero\Delphi\fmx\FMX.Objects3D.pas
V:\Embarcadero\Delphi\fmx\FMX.PhoneDialer.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.Pickers.pas
V:\Embarcadero\Delphi\fmx\FMX.Pickers.Default.pas
V:\Embarcadero\Delphi\fmx\FMX.Pickers.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.PixelFormats.pas
V:\Embarcadero\Delphi\fmx\FMX.Platform.pas
V:\Embarcadero\Delphi\fmx\FMX.Platform.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.Platform.Mac.pas
V:\Embarcadero\Delphi\fmx\FMX.Platform.Win.pas
V:\Embarcadero\Delphi\fmx\FMX.Printer.pas
V:\Embarcadero\Delphi\fmx\FMX.StdActns.pas
V:\Embarcadero\Delphi\fmx\FMX.StdCtrls.pas
V:\Embarcadero\Delphi\fmx\FMX.Styles.pas
V:\Embarcadero\Delphi\fmx\FMX.TabControl.pas
V:\Embarcadero\Delphi\fmx\FMX.TextLayout.pas
V:\Embarcadero\Delphi\fmx\FMX.TextLayout.GPU.pas
V:\Embarcadero\Delphi\fmx\FMX.TreeView.pas
V:\Embarcadero\Delphi\fmx\FMX.Types.pas
V:\Embarcadero\Delphi\fmx\FMX.Types3D.pas
V:\Embarcadero\Delphi\fmx\FMX.Viewport3D.pas
V:\Embarcadero\Delphi\fmx\FMX.VirtualKeyboard.iOS.pas
V:\Embarcadero\Delphi\fmx\FMX.WebBrowser.pas

Или вот:

V:\Embarcadero\Delphi\databinding\components\Data.Bind.Components.pas
V:\Embarcadero\Delphi\databinding\components\Data.Bind.DBScope.pas
V:\Embarcadero\Delphi\databinding\components\Data.Bind.Grid.pas
V:\Embarcadero\Delphi\databinding\components\Data.Bind.ObjectScope.pas
V:\Embarcadero\Delphi\databinding\components\Fmx.Bind.Editors.pas
V:\Embarcadero\Delphi\databinding\engine\System.Bindings.Factories.pas

Ну или вот:

V:\Embarcadero\Delphi\Indy10\Protocols\IdAttachment.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAttachmentFile.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAttachmentMemory.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAuthentication.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAuthenticationDigest.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAuthenticationManager.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdAuthenticationSSPI.pas
V:\Embarcadero\Delphi\Indy10\Core\IdBuffer.pas
V:\Embarcadero\Delphi\Indy10\Core\IdCmdTCPClient.pas
V:\Embarcadero\Delphi\Indy10\Core\IdCmdTCPServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCoder.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCoder00E.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCoderMIME.pas
V:\Embarcadero\Delphi\Indy10\Core\IdCommandHandlers.pas
V:\Embarcadero\Delphi\Indy10\Core\IdContext.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCookie.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCookieManager.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdCustomHTTPServer.pas
V:\Embarcadero\Delphi\Indy10\Core\IdCustomTCPServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDateTimeStamp.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDICT.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDICTCommon.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDNSCommon.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDNSResolver.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdDNSServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdEMailAddress.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdExplicitTLSClientServerBase.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFSP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPCommon.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListOutput.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseAS400.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseBase.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseDistinctTCPIP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseEPLF.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseIEFTPGateway.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseKA9Q.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseMicrowareOS9.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseMPEiX.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseMusic.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseMVS.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseNCSAForDOS.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseNovellNetware.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseNovellNetwarePSU.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParsePCNFSD.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseStercomOS390Exp.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseStratusVOS.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseTandemGuardian.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseTOPS20.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseTSXPlus.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseUnisysClearPath.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseUnix.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseVM.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseVMS.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseVSE.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseVxWorks.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseWfFTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseWindowsNT.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListParseXecomMicroRTOS.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPListTypes.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdFTPServer.pas
V:\Embarcadero\Delphi\Indy10\System\IdGlobal.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdGlobalProtocols.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdGopher.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHash.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHeaderCoderBase.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHeaderList.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHMAC.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHTTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHTTPHeaderInfo.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHTTPProxyServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdHTTPWebBrokerBridge.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIcmpClient.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdIMAP4.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdIMAP4Server.pas
V:\Embarcadero\Delphi\Indy10\Core\IdInterceptSimLog.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIOHandler.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIOHandlerSocket.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIOHandlerStream.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIPAddress.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdIPAddrMon.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIPMCastClient.pas
V:\Embarcadero\Delphi\Indy10\Core\IdIPMCastServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdIPWatch.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdIRC.pas
V:\Embarcadero\Delphi\Indy10\Core\IdLogFile.pas
V:\Embarcadero\Delphi\Indy10\Core\IdLogStream.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdLPR.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMailBox.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMappedFTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMappedPOP3.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMappedPortTCP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMappedPortUDP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessage.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageBuilder.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageClient.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoder.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoderBinHex4.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoderMIME.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoderQuotedPrintable.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoderUUE.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCoderYenc.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMessageCollection.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdMultipartFormData.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdNetworkCalculator.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdNNTPServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdOTPCalculator.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdPOP3.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdPOP3Server.pas
V:\Embarcadero\Delphi\Indy10\Core\IdRawBase.pas
V:\Embarcadero\Delphi\Indy10\Core\IdRawFunctions.pas
V:\Embarcadero\Delphi\Indy10\Core\IdRawHeaders.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdRemoteCMDClient.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdRemoteCMDServer.pas
V:\Embarcadero\Delphi\Indy10\Core\IdReply.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdReplyIMAP4.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdReplySMTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSASL.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSASL_CRAM_MD5.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSASL_CRAM_SHA1.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSASLCollection.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSASLDigest.pas
V:\Embarcadero\Delphi\Indy10\Core\IdScheduler.pas
V:\Embarcadero\Delphi\Indy10\Core\IdSchedulerOfThread.pas
V:\Embarcadero\Delphi\Indy10\Core\IdSchedulerOfThreadPool.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdServerInterceptLogBase.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdServerInterceptLogFile.pas
V:\Embarcadero\Delphi\Indy10\Core\IdServerIOHandlerSocket.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSMTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSMTPBase.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSMTPRelay.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSMTPServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSNMP.pas
V:\Embarcadero\Delphi\Indy10\Core\IdSocketHandle.pas
V:\Embarcadero\Delphi\Indy10\Core\IdSocks.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSocksServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSSL.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSSLOpenSSL.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSSLOpenSSLHeaders.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSSLOpenSSLUtils.pas
V:\Embarcadero\Delphi\Indy10\System\IdStack.pas
V:\Embarcadero\Delphi\Indy10\System\IdStackBSDBase.pas
V:\Embarcadero\Delphi\Indy10\System\IdStackVCLPosix.pas
V:\Embarcadero\Delphi\Indy10\System\IdStackWindows.pas
V:\Embarcadero\Delphi\Indy10\Core\IdSync.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSysLog.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSysLogMessage.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSysLogServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSystatServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdSystatUDPServer.pas
V:\Embarcadero\Delphi\Indy10\Core\IdTask.pas
V:\Embarcadero\Delphi\Indy10\Core\IdTCPConnection.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdTelnet.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdTelnetServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdText.pas
V:\Embarcadero\Delphi\Indy10\Core\IdThread.pas
V:\Embarcadero\Delphi\Indy10\Core\IdThreadComponent.pas
V:\Embarcadero\Delphi\Indy10\Core\IdThreadSafe.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdTrivialFTP.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdTrivialFTPServer.pas
V:\Embarcadero\Delphi\Indy10\Core\IdUDPBase.pas
V:\Embarcadero\Delphi\Indy10\Core\IdUDPClient.pas
V:\Embarcadero\Delphi\Indy10\Core\IdUDPServer.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdUserAccounts.pas
V:\Embarcadero\Delphi\Indy10\Protocols\IdVCard.pas

Для МЕНЯ ЛИЧНО - "вопрос про FreeAndNil" - ЗАКРЫТ.

Его НАДО использовать!

БЕЗДУМНО, если хотите.

И ЕЩЁ РАЗ сошлюсь на gunsmoker'а - http://www.gunsmoker.ru/2009/04/freeandnil-free.html

ЕЩЁ РАЗ цитата:
"Итак.

Так зачем же медлить? Почему бы, начиная с сегодняшнего дня, везде (где это возможно) использовать FreeAndNil вместо Free? Если вы сделаете это своей привычкой - вы ничего не потеряете, а, наоборот, приобретёте немалые бонусы.

Я не единожды сталкивался с трудно выловимыми багами в чужом коде со сложной иерархией классов. Потратив несколько часов на бесплодные попытки найти источник проблем "в лоб", просто тупо заменив все Free на FreeAndNil, проблема находилась сразу же (но вот над решением проблемы приходилось ещу долго думать).

Тем не менее, я подозреваю, что большинство людей, даже если они согласятся с приведённой выше аргументацией, не будут ломать свои привычки только по той причине, что "кто-то там что-то сказал". Они не встречались с такой ситуацией - значит, её нет (пока гром не грянет...). Как я уже сказал, FreeAndNil - это ремни безопасности. Пока какой-нибудь косяк не ударит вас сильно по носу, вы, скорее всего, не будете его использовать. Но уж будьте уверены, что когда он ударит - это будет весьма болезненно. Вы можете потратить на отладку кучу времени.

Примечание: всё вышесказанное является только моим мнением. Я просто высказал точку зрения и привёл её аргументацию. Следовать этой рекомендации или нет - целиком ваше решение и я приму его, какое бы оно ни было. Если вы признали, что подобная точка зрения имеет право на жизнь - моя задача выполнена."

ВСЁ! ЕЩЁ РАЗ - "для меня лично" - ВОПРОС ЗАКРЫТ.

Пожалуйста - не пытайтесь меня "троллить" по этому вопросу 1024-й раз...

27 комментариев:

  1. Молчал-молчал, но раз уж ты эту тему так активно раз за разом поднимаешь, выскажусь наконец. Была у Льва Николаевича Толстого такая статья: "Не могу молчать" :)

    Не могу заставить себя серьезно воспринимать настолько детскую аргументацию:
    Я не единожды сталкивался с трудно выловимыми багами в чужом коде со сложной иерархией классов. Потратив несколько часов на бесплодные попытки найти источник проблем "в лоб", просто тупо заменив все Free на FreeAndNil, проблема находилась сразу же (но вот над решением проблемы приходилось ещу долго думать).

    Ты ведь понимаешь, что если бы он с самого начала использовал FreeAndNil, то об этом проблеме он бы даже НЕ УЗНАЛ и не стал бы ее решать? Это удобно конечно, успокаивает, но я о проблемах предпочитаю знать. Ты ведь понимаешь, что если Free без моего ведома повторно вызывается, то ситуация явно нештатная и неплохо бы о ней знать?

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

    try
    // какой-то код
    except
    // пусто, ничего не делаем
    end;

    Но "спрятанные" эксепшены не избавляют тебя от багов. Программа не перестает неправильно работать. Зачем я это говорю, если для нас обоих это очевидно?

    Я использую FreeAndNil в тех случаях, когда я сам допускаю, что Free может ШТАТНО вызываться более одного раза - иногда такое нужно. Но применять его ВСЕГДА? Брать это за ПРАВИЛО? Ну мы же взрослые люди, не будем пытаться закрывать уши ладошками и зажмуриваться вместо того, чтобы честно поймать свой эксепшен и НА САМОМ ДЕЛЕ РЕШИТЬ ПРОБЛЕМУ (да, это трудно, но программирование всегда было не для слабых духом) :)

    P.S. Не хочу и не пытаюсь тебя троллить, но как я уже заметил - не смог промолчать. Если удалишь этот комментарий, не обижусь.

    ОтветитьУдалить
    Ответы
    1. Ром, ну что делать - "твоя практика остаётся твоей практикой", а "моя практика остаётся моей".

      "Доказывать" никому ничего не буду. Бестолку. Это я уже давно понял.

      Зачем это было написано (в смысле пост)? Ну чтобы уж "перестали цепляться" к моим FreeAndNil. Только и всего.

      А то ну прям на "каждый" FreeAndNil - находятся "любители откомментировать".

      Про exception'ы ты пример хороший привёл, но по-моему к теме не относящийся.

      "когда я сам допускаю, что Free может ШТАТНО вызываться более одного раза - иногда такое нужно" у меня почему то такое случается не "ИНОГДА", а "сплошь и рядом".

      Я могу попытаться "объяснить почему":
      1. У меня повсеместно используется подсчёт ссылок.
      2. У меня используется кеширование экземпляров классов (и стандартных тоже).

      Ну и "просто к слову" - я ЛИЧНО "изобрёл" FreeAndNil - когда его у Borland'а и в помине не было. Вот "почему-то" - "изобрёл". Не буду пытаться "поднять волны памяти", но думаю, что "не просто так".

      Удалить
    2. Да, не будем спорить, смысла в этом мало. Просто захотелось высказаться, со мной такое бывает :) Надеюсь, ты не воспринял это слишком лично.

      Удалить
    3. "Надеюсь, ты не воспринял это слишком лично. "

      Ну скажем так - "рабочие моменты я стараюсь не воспринимать лично" :-) Хотя иногда - "заносит".

      Всё же для меня - "работа - это жизнь".

      Твои доводы мне - понятны.

      Но поверь мне - я их уже не раз слышал :-)

      Я попытался "аргументировать свою позицию". Но видимо - плохо выходит. Ну что делать.

      Твой опыт - это твой опыт, мой опыт - это мой опыт.

      Какой из них лучше? Да никакой :-)

      Всё равно ведь - "программы работают" :-)

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

      Технологии же (и технологические приёмы) это не "предмет для спора",а "повод для обмена мнениями". ;-)

      Удалить
    4. Вдогонку...

      Вот если бы вместе работали и результат твоей работы зависел бы от моей и наоборот - тогда бы я СПОРИЛ бы :-)

      Но там было бы гораздо меньше "абстрактных рассуждений". С обоих сторон.

      Удалить
    5. "Но там было бы гораздо меньше "абстрактных рассуждений". С обоих сторон."

      -- ну в смысле "поле для спора" сильно сузилось бы. До конкретных примеров.

      А так - я не знаю твоей специфики, а ты моей.

      Что собственно и подогревает бесконечные "интернет-холивары". Ну я не про наш с тобой случай. А так - "к слову".

      Удалить
    6. Кстати про "воспринять слишком лично".

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

      Но! "Втихую" делать по-своему. А не пытаться "евангелировать". А если дело доходит до разборок "а почему ты так сделал" - аргументировать свою позицию. По каждому конкретному случаю. И либо "убедить" в ДАННОМ КОНКРЕТНОМ случае, либо признать, что в ДАННОМ КОНКРЕТНОМ случае был неправ.

      А дальше уже идёт счёт "плюсов" и "минусов" по конкретным случаям и набирается статистика.

      Ну понятное дело, что если "обе стороны" готовы "взаимодействовать", а не "просто спорить".

      Но это уже опять же к вопросу о "сужении поля для спора". Не "вообще" всякие "кони в вакууме", а вполне "конкретные случаи".

      Удалить
    7. "Ну например он твой начальник. Ну или мама с папой."

      ну или ты "просто ценишь этого человека", но имеешь своё мнение и он тебя не убедил.

      Удалить
    8. Да! Это просто из серии "заметок", а не в коем случае не из разряда "нравоучений".

      Я наверное тут скорее просто "мысли вслух" озвучиваю.

      Удалить
  2. Да, так просто закрыть тему не получится )

    Лично про себя: не сказал бы я, что я не любитель FreeAndNil. Но я не использую его повсеместно, я за то, чтобы его использовать везде, где это действительно надо (ну чтобы не писать две строчки Obj.Free; Obj := nil).

    У FreeAndNil есть ещё одна особенность - сначала Nil, потом Free. Это даже хорошо, есть сценарии где это полезно, но сначала сбивает с толку.

    P.S.: насчёт FM - я думаю, что там FreeAndNil используется именно для того, чтобы задействовать ARC. Вообще с введением ARC, который может быть то включен, то выключен - логично и правильно использовать только FreeAndNil.

    ОтветитьУдалить
    Ответы
    1. насчёт FM - я думаю, что там FreeAndNil используется именно для того, чтобы задействовать ARC. Вообще с введением ARC, который может быть то включен, то выключен - логично и правильно использовать только FreeAndNil.

      Логично и правильно работать по-старому, используя Free. На старых платформах это будет Free, а на новых превратиться в ":= nil" :)

      Удалить
    2. не понял... предлагаешь повсеместно писать {$ifdef AUTOREFCOUNT} Obj := nil {$else} Obj.Free {$endif}?
      тогда уж лучше FreeAndNil(Obj), там директивы спрятаны внутри..

      Удалить
    3. Посмотри как реализован Free, там уже все это написано.

      Удалить
    4. Видимо мы друг друга не понимаем. TObject.Free при включённом ARC не делает ничего, поэтому его вызов (для ARC) не несёт никаких последствий.

      Если я хочу, чтобы мой код работал и там, и там, я могу написать несколько вариантов:
      а): Obj.Free; Obj := nil;
      б): {$ifdef AUTOREFCOUNT} Obj := nil {$else} Obj.Free {$endif};
      в) FreeAndNil(Obj);

      Вот из этих всех трёх я бы предпочёл последний.

      Удалить
    5. Он не не делает ничего. При компиляции Obj.Free автоматически заменяется на Obj := nil;

      procedure TObject.Free;
      begin
      // under ARC, this method isn't actually called since the compiler translates
      // the call to be a mere nil assignment to the instance variable, which then calls _InstClear
      {$IFNDEF AUTOREFCOUNT}
      if Self <> nil then
      Destroy;
      {$ENDIF}
      end;

      Удалить
    6. эээ... да, этого я недоглядел. И теперь понял смысл твоего комментария про "по-старому, используя Free".
      Действительно, Obj.Free с ARC работает как Obj := nil...

      Это конечно хорошо, но выглядит это всё... прямо скажем не очень.

      Удалить
    7. "Вообще с введением ARC, который может быть то включен, то выключен - логично и правильно использовать только FreeAndNil"

      Вот вот :-)

      "подсчёт ссылок"... Писал об этом выше. Только я "придумал" это почти на 20-ть лет раньше Embarcadero.

      Удалить
    8. "У FreeAndNil есть ещё одна особенность - сначала Nil, потом Free."

      И это - КРАЙНЕ правильно :-).

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

      У меня когда-то был "скажем так" InvertedFreeAndNil. Ну для "таких случаев". Точнее l3FreeGlobalObject.

      Но я от него - избавился в конце-концов.

      И ещё...

      Пока "ты работаешь один" и код "не сильно перемешивается", то Free или FreeAndNil - в общем всё равно. Но как только код "становится общим" - тут сразу появляется необходимость в использовании ИМЕННО FreeAndNil.

      Ну что собственно Роман косвенно подтвердил словами "когда надо я пишу Free, а когда надо - FreeAndNil".

      Только - тут становится не "я знаю", а "третий парень", а то и "десятый".

      Удалить
    9. procedure l3FreeGlobal(var P);
      {* - освобождает ГЛОБАЛЬНЫЙ объект со счетчиком ссылок и очищает переменную P ПОСЛЕ освобождения объекта.
      Нужна для того, чтобы в процессе его освобождения была возможность обращаться к правильному экзаемпляру глобального объекта. }

      Удалить
    10. l3FreeGlobal
      наврал, что "совсем избавился". Сейчас посмотрел - используется в ОДНОМ только месте из ВСЕХ проектов.

      Удалить
    11. Более того скажу - СТАНДАРТНАЯ ПРАКТИКА "разборок с проблемами в "чужом коде"" у "меня лично" начинается с "бездумной замены всех Free на FreeAndNil". Потом прогон всех возможных тестов тестов на предмет "а что поменялось". Потом прогон на "утечки памяти". И только ПОСЛЕ ЭТОГО - локализация и ОСМЫСЛЕНИЕ проблемы. И эта практика за ДОЛГИЕ ГОДЫ - себя БОЛЕЕ чем оправдывает.

      Вреда для АРХИТЕКТУРЫ проектов и/или библиотек при замене Free на FreeAndNil - я пока не нашёл. Ни разу. При такой замене архитектура только "выправляется". При ОБРАТНОЙ замене - "возможны варианты".

      Удалить
    12. Ну и ещё добавлю - FreeAndNil позволяет "автоматически" и на корню убивать подобные конструкции:

      f_SomeMyObject.SomeMyProperty.Free
      или
      f_SomeMyObject.SomeMyFunction.Free

      которые (на МОЙ "вкус") - уж БОЛЕЕ чем "дурно пахнут".

      Удалить
    13. "При такой замене архитектура только "выправляется"."

      -- появляются "изолированные" singleton'ы, а не просто "глобальные объекты".
      -- появляются связки publisher/subscriber, а не просто "объекты знают друг про друга".
      -- появляются фабрики (и Dependecy Injection кстати), а не просто "давайте создадим объект, про котоый знаем "все кишки"".
      -- появляются "кеши объектов", а не просто "давайте попробуем использовать объект повторно".

      Что МЕНЯ лично только РАДУЕТ.

      Удалить
    14. - появляется чёткое представление о том - "кто кем владеет". Кто держит "мягкую ссылку", а кто - "жёсткую".

      Ну понятно, что всё что "я тут сказал" - это "абстрактные слова", не подкреплённые конкретными примерами. Ну вариантов тут несколько:
      -- поверить мне на слово.
      -- не согласиться.
      -- задать вопросы о конкретных примерах.
      -- наверное что-то ещё

      :-)

      Удалить
    15. "Ну и ещё добавлю - FreeAndNil позволяет "автоматически" и на корню убивать подобные конструкции:"

      Я кстати не зря писал вот это - http://18delphi.blogspot.ru/2013/05/blog-post_7587.html

      Рома правда и там со мной спорил.

      Удалить
    16. Что ещё добавлю?

      НЕЛЬЗЯ "просто так" взять и "позвать на объекте метод Free". Для ЭТОГО надо обладать "объектной ссылкой". Да ещё и "жёсткой".

      Было бы здорово, чтобы ЯЗЫК это КОНТРОЛЛИРОВАЛ.

      ARC (да и "сборка мусора") - это ГАРАНТИРУЮТ, но к сожалению - не позволяют "экономить на спичках".

      Кто ещё "гарантирует"?

      Скажу - C++ с его статическими объектами (на стеке или в контексте других объектов) и Smart-Pointer'ами.

      Понятное дело, что C++ это язык который "легко может позволить "выстрелить себе в ногу"".

      Но! В отличии от Delphi, который вроде и БОЛЕЕ СИЛЬНО ТИПИЗИРОВАННЫЙ - C++ позволяет сделать так, чтобы "стрелять себе в ногу" и не захочется.

      Удалить
  3. Этот комментарий был удален автором.

    ОтветитьУдалить