RAII қол жетімді болған кезде қоқыс жинауға не үшін қажет?

C ++ 14 стандартты кітапханасының қоқыс жинағышын енгізу туралы сөйлесуді естимін. Бұл ерекшеліктің негізі қандай? Бұл RAII C ++ жүйесінде бар ма?

  • Стандартты кітапхана қоқыс жинаушысының RAII семантикасына қалай әсер етеді?
  • Мен үшін (бағдарламашы) немесе C ++ бағдарламаларын қалай жазатыным маңызды?
41
@Ze, std :: shared_ptr бұл мәселені талғаммен шеше алмайды? мысалы, келесідегі өрістің түрі ретінде Node * орнына std :: shared_ptr пайдаланыңыз.
қосылды автор xmllmx, көзі
Сондай-ақ, Хер айтқандай емес БАРЛЫҚ қоқыс жинау керек, тек қана құлыпсыз затпен байланысты заттар. Ол сондай-ақ GC дәл болуы керек дейді.
қосылды автор Ali, көзі
Құлыптан босатылған нәрсе қарапайым: жадты ағызуға мүмкіндік беретін көптеген құлыпсыз алгоритмдер өте қарапайым.
қосылды автор R. Martinho Fernandes, көзі
Мен Хербтің құлпырасыз бағдарламалаудағы кейбір жағдайларда өте пайдалы болатынын естігенімде естідім, бірақ мен бұл туралы көп білмеймін, жауап бермеймін
қосылды автор Andy Prowl, көзі
C ++ 14 туралы GC алу туралы қай жерде естіген едіңіз? Өйткені ол, әрине, қазіргі жұмыс жобасында жоқ.
қосылды автор Nicol Bolas, көзі
@AndyProwl: дәл осында. Жақсы білетін адам жауап беруге тырысады деп үміттенеміз.
қосылды автор Alok Save, көзі
@ R.MartinhoFernandes: мысал келтіріп, түсіндіріңіз?
қосылды автор Xeo, көзі
C ++ мақсаты - C немесе .NET сияқты тордағы құс емес, ол барлық жерде микроконтроллерлерден серверлерге қолданылады, күтпеген утилиталар жаңа қауіптерді енгізе алады және жадқа толық бақылау басқарылатын тілдерге қарағанда C ++ артықшылықты етеді.
қосылды автор fatihk, көзі
AFAIK стандарты тек біреуін іске асыру үшін жеткілікті GC туралы қамқорлық етеді, сондықтан оны кейбір жадты басқарудың қосымша тәсілі ретінде қолдануға болады. GC RAII-ны немесе ол негізделген шектік нысанның қызмет ету мерзімін алмастырмайды.
қосылды автор josefx, көзі
@xmllmx shared_ptr жеткіліксіз. Shared_ptr файлының мазмұнын оқып шығатын және түйінді жойатын жайт арқылы дереу алдын-ала босатылған жіпті елестетіңіз. Орындауды жалғастырған кезде, ол оқылған мазмұнның әлі де жарамды екенін анықтаудың ешқандай мүмкіндігі жоқ, себебі ол рефcount-ды ешқашан көбейтпеді және түйінді босатуға арналған жоятын жіп үшін мүлдем заңды болатын. Бұл қиын мәселе, бірақ оны EBR, RCU, қауіпті көрсеткіштер, толық сипаттамалы GC немесе контекстік-сезімтал шешімдер арқылы шешуге болады.
қосылды автор Ze Blob, көзі
@Xeo Мысал ретінде байланыстырылған тізімнен элементті алып тастаңыз. Оны жою өте қарапайым, қарапайым құм және сіз жасалды ... Жақсы емес; түйінді қалай қашан қауіпсіздендіру қауіпсіз? Басқа да ағындардың кез-келген саны қазіргі кезде осы түйінге сілтеме жасай алады және оны жоюдың қауіпсіздігін анықтау өте қиын. GC бұл проблеманы оңай өңдейді, ол басқа ағын арқылы барлық сілтемелерді жіп қауіпсіз түрде жасайды. Мен өзімнің жеке басылымдарым бойынша өте аз инвазивті болып табылатын және көп нәрсеге ие болатын RCU -ді ұнатамын Linux ядросындағы сәттілік.
қосылды автор Ze Blob, көзі

7 жауаптар

Қоқысты жинау және RAII әртүрлі контексте пайдалы. GC бар болуы RAII-ді қолдануыңызға әсер етпеуі керек. RAII жақсы танымал болғандықтан, GC пайдалы болатын екі мысалды келтіремін.


Қоқыс жинау құлыпсыз деректер құрылымдарын енгізуде үлкен көмек болар еді.

[...] детерминистикалық жадты босату дерексіз деректер құрылымдарында түбегейлі мәселе болып табылады. ( Lock-Free Деректер құрылымдары , Андрей Александреску)

Негізінен бұл мәселе жіпті оқып жатқанда жадты бөлмейтіндігіңізге көз жеткізу керек. GC қолайлы болып табылады: ол жіптерге қарап, қауіпсіз болған кезде ғана таратуға болады. Толық ақпарат үшін мақаланы оқыңыз.

Тек мұнда түсінікті болу үшін: бұл WHOLE WORLD Java-дегідей қоқыс жиналуы керек дегенді білдірмейді; тек қана тиісті деректер қоқыс жинауға тиіс.


Bjarne Stroustrup өзінің презентацияларының бірінде GC-дің қолайлы болатындай жақсы, жарамды мысалы берді. C/C ++, 10M SLOC-де жазылған өтінімді елестетіп көріңіз. Өтінім өте жақсы жұмыс істейді (өте қатесіз), бірақ ол ағып кетеді. Сізде ресурстарды (адам сағаттары), сондай-ақ функционалды білімдеріңіз оны түзете алмайды. Бастапқы коды - бұрынғыдан да қатал мұраланған код. Сен не істейсің? Мен GC-мен кілем астында проблеманы жеңудің ең қарапайым және арзан әдісі екеніне келісемін.


sasha.sochka сілтегендей, қоқыс жинаушы міндетті емес болады.

Менің ойымша, адамдар Java-де қолданылғандай GC-ны қолдануға кіріседі және қисынды коды жазады және қоқыс жинайды. ( unique_ptr ) немесе, hell, stack allocation мұны істейтін болса да, shared_ptr әлдеқашан әдепкіде «өту» деген әсер бар.)

30
қосылды
біреу бжарнаға вальгринд туралы айту керек: Р
қосылды автор NoSenseEtAl, көзі
@NoSenseEtAl valgrind көп көмектесе алмады. Егер кодекс бұзылған болса және сізде функционалды білім болмаса, ағып кетуді түзетуге өте қиын болуы мүмкін. Өкінішке орай, көптеген компанияларда бұл проблема бар (бұл дегеніміз, ескірген кодты және осы кодта жұмыс істеуге дайын және дайын бола алатын өте аз әзірлеушілерді білдіреді).
қосылды автор Ali, көзі
@akappa: неге қоқыс жинаушыға теңдестірілген өнімділікпен бірдей нәрселер жасай алатын болса, еске қолмен біріктіруге болады?
қосылды автор Alex, көзі
@akappa: GC C ++-ге қосылатын болса, бұл әлі де c ++ деп үміттенемін. Мағынасы: өнімділікке шығатын барлық нәрсе қосылады. (оны пайдаланудың қажеті жоқ). Және смарт-ұпайлардан гөрі өнімділік жақсы болғанда, GC-ға ие болу да жақсы. Мен қолмен жазу кодының орнына тілдік функция ретінде өте жақсы болғандықтан, ақылды көрсеткіш + бассейн + теңшелетін деаллокаторды деаллокауларды кейінге қалдыру және қабат қысымын азайту үшін жаздым.
қосылды автор Alex, көзі
Қоқыс жинау, егер сіз жинауды пайдалану қажет болса, ыңғайлы болады, бірақ объектілерді босату өте жиі орын алады. Қоқыс жинау мүмкіндігін босатуға мүмкіндік береді, әзірге жад жеткіліксіз болады, содан кейін барлық жадты бірден жинайды. егер сіз бағдарламаны жады пулдарын немесе тегін тізімдерді пайдалану үшін оңтайландырмаған, бірақ бұл мәселеден зардап шексе, ол осы фактіден пайда көруі мүмкін.
қосылды автор Alex, көзі
@Alex: осындай нәрсені өңдеудің басқа тәсілдері бар, мысалы, пайдаланушыға бөлу/деаллокаторлар және смарт-көрсеткіш
қосылды автор akappa, көзі
@Alex: Кітапханаға негізделген, инвазивті және ашық шешімдерін «GC-ді C ++-ге ендіруге» ұқсас, бұл өте инвазивті және нәзік дыбыстарды жасайды. Бірақ бұл жай ғана менің артықшылығым, сондықтан адамдар неге басқаша істейтінін түсінемін.
қосылды автор akappa, көзі

GC жоқ жазудың күрделі/тиімсіз/мүмкін емес кейбір алгоритмдері бар. Мен C ++-де GC-тің басты сатылым нүктесі деп ойлаймын және оның жалпы мақсаттағы таратушы ретінде пайдаланылуын көре алмаймын.

Неліктен жалпы мақсаттағы бөлінуші?

Біріншіден, бізде RAII бар және көпшілігі (мені қоса) бұл ресурстарды басқарудың жоғары әдісі деп санайды. Біз сияқты детерминизмді ұнатамыз, себебі ол сенімді, ашық кодты әлдеқайда қарапайым етеді және өнімділікті алдын-ала болжайды.

Екіншіден, сіз кейбір C-C ++-ді - жадты қалай қолдануға болатын шектеулерді орналастыруыңыз қажет. Мысалы, сіз кем дегенде бір қол жетімді, мұқалмаған көрсеткіш қажет. Басқалар арасында ортақ ағаш контейнер кітапханаларында танымал болып табылған (түсті жалаушаларға арналған кепілдік берілген төмен биттерді пайдаланып) танылмаған көрсеткіштер GC танылмайды.

Осыған байланысты, заманауи GC-ті қолдануға ыңғайлы нәрселер C ++-ке қолдануға өте қиын болады, егер сіз кез-келген « кез-келген қолдайтын көрсеткіштерді қолдайтын болсаңыз. Генеральды дефрагменттеу ГС-лары шынымен керемет, өйткені бөлу өте арзан (нақты көрсеткішті көбейте отырып) және ақыр соңында сіздің қаражатыңыз жақсартылған жермен азайтылады. Ол үшін объектілерді жылжыту қажет.

Объектіні қауіпсіз жылжыту үшін, GC оған барлық көрсеткіштерді жаңарта алады. Ол зақымданғандарды таба алмайды. Бұл қоныстандыруы мүмкін, бірақ әдемі болмайды (мүмкін gc_pin типі немесе ұқсас, қолданыстағы std :: lock_guard сияқты пайдаланылады) ). Ыңғайлылық есіктерден тыс еді.

Істер қозғалысынсыз, GC басқа жерде қолданылатыннан гөрі едәуір баяу және аз масштабталатын болады.

Мүмкіндік себептері (ресурстарды басқару) және тиімділік себептері (жылдам, жылжымалы шығындар), GC тағы қандай? Әрине, жалпы мақсат емес. Құлыпсыз алгоритмдерді енгізіңіз.

Неге құлыпсыз?

Құлыптылықсыз алгоритмдер жұмыс істей отырып, деректерді құрылыммен уақытша «синхрондаудан» шығып, кейінірек оны анықтау/түзету арқылы жұмыс жасайды. Мұның бір әсері, егер ол жойылғаннан кейін, есте сақтау жадына кіруге болады. Мысалы, егер сізде LIFO-дан түйін түйініне бәсекелесетін бірнеше ағындар болса, басқа бір жіп түйін қазірдің өзінде қабылданғанын білмей тұрып, бір жіпті поп жасап, түйінді жоюға болады:

А тармағы:

  • Тамыр түйініне көрсеткішті алыңыз.
  • Түбірлік түйіннен келесі түйінді көрсетіңіз.
  • тоқтату

В-ны:

  • Тамыр түйініне көрсеткішті алыңыз.
  • тоқтату

А тармағы:

  • Поп-түйін. (түбірлік түйін көрсеткіші оқылғаннан кейін өзгермеген болса, түбірлік түйін сілтегішті келесі түйін сілтегішімен ауыстырыңыз.)
  • Түйінді жою.
  • тоқтату

В-ны:

  • «Синхрондаудан» шыққан түбірлік түйіннің сілтегішінен келесі түйінге жүгіргіні алыңыз және оны жойып тастасақ,

GC көмегімен жадыдағы оқи алмаудан аулақ бола аласыз, себебі түйін оны ешқашан жоя алмайды, ал В-ны сілтеме жасайды. Осыған байланысты жолдар бар, мысалы, қауіпті көрсеткіштері немесе Windows жүйесіндегі SEH ерекшеліктерін ұстап қалу, бірақ олар өнімділікті айтарлықтай төмендетуі мүмкін. GC мұнда ең оңтайлы шешім болып табылады.

11
қосылды
Құлық сілтемесінің қиындықтарынан аулақ болуға болады, бірақ кодты көшіруді қалайтын кез келген жолдың мазмұнын көшіруге болады, бұл айтарлықтай орындау уақытының құнын қосуы мүмкін. Бұл жадты тұтынуды арттырады және көшіру жолдарын өткізуге жұмсалатын уақытты ұлғайтады ғана емес, сонымен қатар, сілтеме теңдейтін жолдарды жылдам анықтауға кедергі келтіреді. RAII-ді қолдау мүмкін болатын жолдарды ажырату үшін пайдаланылуы мүмкін, олар біреуден артық сілтеме бола алмайды, бұл «мүмкін», сондықтан бір сілтеме болуы мүмкін жолдарды жергілікті түрде өзгертуге мүмкіндік береді, бірақ GC жолдар үшін жақсы.
қосылды автор supercat, көзі
Мұндай деректер құрылымдары GC қарағанда RAII жақсы жұмыс істей алады, бірақ олар көрінбейтін көрінеді. Сызықтар өте жиі кездеседі және GC-ді RAII-ге қарағанда жақсы жұмыс істей алады (бірақ олар екеуі де қолдау көрсететін тілде жақсы жұмыс істей алады). Тұрақты жол сілтемесі кез-келген GC жүйесінде құрастырылған немесе жойылған сайын, бұл сілтеме соңғы болып табылатынын анықтау үшін атомдық операцияларды пайдалану қажет. Атомдық операциялар көп процессорлық жүйелерде қымбат. GC жүйесінде жол сілтемесін сақтау сілтемесін көшіруден басқа ештеңе талап етпейді.
қосылды автор supercat, көзі
Иә, құлыпсыз LIFO басылған түйінді оқи алады. Бұл күтілетін мінез-құлық. GC-мен сіз delete емес едік, сондықтан мүмкін болмаған жадыға рұқсат болмайды.
қосылды автор Cory Nelson, көзі
Мен түсіндім, бірақ жеткілікті жақсы түсіндірмеді деп ойлаймын. Кешіріңіз. Құлыптылықсыз LIFO pop() келесідей болады: деректер құрылымының басынан ptr; ptr басынан келесі ptr оқыңыз (ол осы кезде бастапқы басты түйін болмауы мүмкін); егер бастың ptr өзгермеген болса, келесі ptr элементімен деректер құрылымында head ptr параметрін атомды түрде ауыстырыңыз. Осы уақыт ішінде ешқандай құлыптар болмайды, сондықтан Thread A-де «

pop() ортасындағы толық pop() аяқтауға болады. Мәселен, бұл пікірталасқа сәйкес, дерексіз дау таласта ескі деректерді оқып, соңғы қадам атомды түзетеді.

қосылды автор Cory Nelson, көзі
Кез келген бөлу - ауыр (мысалы, көптеген сызықтарды жасау сияқты) бөлу, әдетте, көрсеткішке қарапайым қадам болып табылатындықтан, дефрагментацияланған ГК-де жылдам болады. Мен C ++ сияқты қозғалатын нысандарды қолдай алмайды деп ойлаймын, сондықтан бұл жетістік пайдасы біз үшін болмауы мүмкін.
қосылды автор Cory Nelson, көзі
Сондай-ақ, GC әдепкі бойынша жылдамырақ болуы мүмкін, бірақ әрдайым GC-ны жоқ мәселені жетілдіру үшін жақсартуға болатын оңтайландыру болады. Бассейндер, ареналар және т.б. - жалпыға ортақ стандартты бөлуді пайдалану қажет емес. Бұл тәжірибе ендірілген код пен ойындарда жиі кездеседі.
қосылды автор Cory Nelson, көзі
Менің ойымды білмегендігіңізге күдіктенемін, білмеймін, ол құлап қалмайды, демек, осы мағынада, мен сұрайтынмын: дұрыс болған жағдайда, қол жетімді түйіннің қолда бар екендігін білу керек пе? неге бұл үшін Т секілді B-нің мұндай нақышталған түйінді және оның қай жолмен қолданылатынын пайдалану дұрыс екенін көрсету керек.
қосылды автор pepper_chico, көзі
Бұл түсініктеме құлыпсыз алгоритмдерге қайда байланысты болады? Бұл тек GC-ге міндетті түрде жүгіне алмай шешілетін негізгі жарыс жағдайына ұқсайды. Сіз GC-де айтқаныңыздай, бұл апатқа ұшырамайды, өйткені түйін ешқашан жойылмайды, ал В-бөлімі оған сілтеме жасайды («Б» тақырыбы 2-қадамдағы түбірлік түйінге ғана ие болады), сондықтан, не болып жатқанын оқып, жойылды (4-қадам)?
қосылды автор pepper_chico, көзі

Мен @DeadMG-дің C ++ стандарты бойынша GC жоқ екеніне келісемін, бірақ мен B Stroustrup-дан келесі сілтеме қосқым келеді:

Автоматты қоқыс жинау C ++-қа кіргенде (егер ол жоқ болса)   қосымша болады

Сондықтан Bjarne болашаққа қосылатынына сенімді. Кем дегенде, EWG (Evolution Working Group) төрағасы және ең маңызды комитет мүшелерінің бірі (және ең бастысы, тіл жасаушысы) оны қосқысы келеді.

Егер ол өз пікірін өзгертпесе, оны болашақта қосып, жүзеге асырады деп күтуге болады.

11
қосылды
@ sasha.sochka: менің жауап туралы не ойлайсыз? EWG-тегі адамдармен бір нәрсеге келісетініне сенімді емеспін, бірақ кітапхана арқылы GC-ны іске асыруға тырысқаннан гөрі, GC-тің тілін білудің өте маңызды пайдасы көрінеді.
қосылды автор supercat, көзі
Шын мәнінде, C ++ комитетінің «басы» (немесе дәлірек айтқанда, конвейер) - «Herb Sutter». Bjarne Stroustrup Evolution Жұмыс тобына (EWG) төрағалық етеді.
қосылды автор Cassio Neri, көзі
@supercat, менің ойымша, сіздің жауапыңыз ақылға қонымды. Мен жұмыс тобының жоспарлары туралы ештеңе білмеймін, бірақ Stroustrup GC-ті таңдаудан бас тартуға уәде бергені оны GC-нің өз тілінде жүзеге асыруы үшін өте шынайы етеді. Ескі код GC пайдаланбайды, ал жаңа кодекс кейбір компиляторлық жалаушаны пайдалана отырып, режимді таңдайды. +1
қосылды автор sasha.sochka, көзі

Жоқ, өйткені біреу жоқ. С ++ 11-де C ++-дің тек C ++ 11-інде қолданылатын жалғыз ерекшеліктері бар, олар жай ғана жадты белгілейді, қажет коллекционер жоқ. Сондай-ақ C ++ 14-де болмайды.

Жинаушы Командадан өтіп бара алмайды, менің ойымша.

6
қосылды
@anatolyg: Сұрақ C ++ 14-де қоқыс жинаудың салдары қандай екенін сұрайды. Жоқ, өйткені ешкім жоқ. Бұл оның сұрағына жауап. Менің пікірім - бұл жай ғана жазба.
қосылды автор Puppy, көзі
Бұл сұраққа жауап бермейді. Сіз тіпті неге соншалықты қатты пікіріңіз бар екенін түсіндіре алмайсыз.
қосылды автор anatolyg, көзі
+1; сондай-ақ C ++ 14 комитетінің жобасы қоқыс жинағын енгізбейді: isocpp.org/files/papers /N3690.pdf
қосылды автор Nate Kohl, көзі

Жауаптардың бірде-біреуі қоқыс жинауды тілге қосудың ең маңызды пайдасына тоқталмайды. Тілге қолдау көрсетілетін қоқыс жинау болмаған жағдайда, оған сілтеме жасалған кезде ештеңе жойылмайтынына кепілдік беру мүмкін емес. Нашар, егер мұндай нәрсе орын алса, сілтемесін пайдалану әрекеті кейінірек кез-келген кездейсоқ нысанды манипуляциялауды тоқтатуға кепілдік бермейді.

Өмір сүру мерзімі қалдықтарды жинаушыға қарағанда RAII басқаратын әлдеқайда жақсы нысандар болғанымен, GC барлық нысандарды басқарады, оның ішінде өмір сүру уақыты RAII арқылы бақыланады. Объектінің деструкторы объектіні өлтіріп, оны пайдасыз етуге тиіс, бірақ оның денесін ГК үшін қалдыру керек. Осылайша объектіге кез-келген сілтеме мәйітке сілтеме болады және ол (анықтама) толығымен жойылғанға дейін бір қалады. Тек мәйіттің барлық сілтемелері тоқтатылған кезде, мәйіттің өзі мұны істейді.

Қоқыс жинағыштарды өзіндік тілдік қолдауынсыз жүзеге асыратын тәсілдер бар болса да, осындай іске асырулар немесе GC-ге кез келген уақытша сілтемелерді құруға немесе жоюға (үлкен қиындықтар мен үстемелерді қоса) хабарлауды немесе GC-ті білмейтін тәуекелді іске қосуды талап ету керек олай болмаған жағдайда басқаша шешілмейтін нысанға қатысты болуы мүмкін. GC үшін компиляторлық қолдау осы проблемаларды шешеді.

4
қосылды
... қандай да бір жады синхрондауына мұқтаж болмайды. C ++ -де, егер бірнеше мәрте өзгермейтін нысанды сілтемелер жасай немесе бұза алатын болса, онда егер сілтеме сілтемелерін жаңартқан кезде ескірген сілтемелер сандарын көбейте немесе азайтатын барлық код пайдаланылса, мұндай есептеулердің шығуын болдырмау қиын болуы мүмкін синхрондау.
қосылды автор supercat, көзі
@AndrewDurward: GC нысандары олардан қажеті жоқ екендігі туралы хабарламаны қабылдай алатын жағдайларда, олардан кейін оларды пайдалану әрекеттеріне анық тырнақшаны кодтауға болады. GC мәселені жасырмады - керісінше. Бағдарламаны кездейсоқ орындамаудың орнына, ол қателіктерді анықтайды. Бұдан басқа, C ++-де бұзылуды тудыруы мүмкін көптеген сценарийлер .NET немесе Java-дегі мәселелер болмайды. Мысалы, GC шеңберлерінде ағындар арасында өзгермейтін деректер құрылымдарына сілтемелерді қауіпсіздендіруі мүмкін, ал ағындар сәйкес келетін сілтемелерді пайдалануы мүмкін ...
қосылды автор supercat, көзі
Егер бірдеңе бұзылған нысанға сілтеме қолдануға тырысса, онда сіздің бағдарламаңызда қате бар. Мәселені жасыру үшін GC-ті пайдалану болашақта сізге көмектеспейді.
қосылды автор Andrew Durward, көзі

GC келесі артықшылықтарға ие:

  1. Бағдарламалық көмексіз шеңберлі сілтемелерді өңдеуге болады (RAII-стилімен, шеңберді бұзу үшін weak_ptr пайдалану керек). Сондықтан RAII стилі қолданбасы дұрыс пайдаланылмаса «ағып кетуі» мүмкін.
  2. Белгілі бір нысанға арналған shared_ptr-нің жасау/жоюы қымбат болуы мүмкін, себебі refcount increment/decrement атомдық операциялар болып табылады. Көпжоспарлы қолданбаларда refcounts бар жад орындары «ыстық» орындар болады, жад ішкі жүйесінде көп қысым жасайды. GC бұл нақты мәселеге бейім емес, себебі ол refcounts орнына жететін жиынтықтарды пайдаланады.

Мен GC - бұл жақсы/жақсы таңдау екенін айтпаймын. Мен жай ғана әртүрлі сипаттамалары бар екенін айтып отырмын. Бір артықшылығы болуы мүмкін кейбір сценарийлерде.

4
қосылды
Компилятор қолдайтын қоқыс жинаудың әлдеқайда үлкен артықшылығы - бұл өлі нысанға сілтеме бар болған кезде, ол сол өлі нысанға сілтеме жасайтынына кепілдік береді. Керісінше, RAII пайдалану кезінде, өлі нысанға сілтеме (немесе көрсеткіш) өздігінен кейбір ерікті тірі объектіге қатысты көрінетін дәлел бола алады. Жадтың ағуы нашар, бірақ қате сілтемелер нашар; RAII мүмкін емес сілтемелерді анықталмаған мінез-құлыққа шақырудан аулақ ұстай алмайды, бірақ компилятор қолдайтын қоқыс жинау мүмкін.
қосылды автор supercat, көзі
@MFH Ия, логикалық ағымдар болуы мүмкін, бірақ олар әлдеқайда сирек. Тек сілтеменің циклы бұл тудырмайды. Сіздің мысалыңызда ағып кету тек делегатқа қолжетімді болған жағдайда ғана (оқиғалар өңдегіштері арқылы) мүмкін болады. Егер оқиға жаһандық/статикалық болса, бұл орын алуы мүмкін, бірақ бұл көптеген жағдайларда болмайды. Сондай-ақ, бұл емес болып табылмайды деген мағынада, бұл мүмкін емес, бұл мүмкін емес: оқиғаға қол жетімді болғандықтан, ол кейінірек шақырылуы мүмкін. Егер солай болса, бәрібір қате пайда болды. Тек егер сіз шынымен де ағып кетпесеңіз, бірақ бұл тіпті сирек.
қосылды автор delnan, көзі
RAII бағдарламасында «тонна shared_ptr's» жоқ
қосылды автор Cubbi, көзі
Айта кету керек, тіпті GC-де «ағып кету» мүмкін. Сіз делегаттарды тіркеген кезде оқиға тапсырушысын елестетіңіз, бірақ сіз объектімен аяқталған кезде делегаттарды тіркемеңіз. Тіркеуден бас тартқан сәттен бастап сіз объектіні ағып кетесіз, себебі ол ешқашан GC-де жиналмайды, өйткені оған әлі де сілтеме бар. Енді делегаттың кейбір ірі объектіге сілтемесі бар деп елестетіңіз -> bang!
қосылды автор MFH, көзі

Анықтамалар:

RCB GC: анықтамалық есептеуге негізделген GC.

MSB GC: Mark-Sweep негізіндегі GC.

Quick Answer:

MSB GC стандарты C ++ стандартына қосылуы керек, себебі ол кейбір жағдайларда RCB GC-ден қарағанда ыңғайлы.

Екі иллюстрациялық мысалдар:

Бастапқы өлшемі кішкентай болып табылатын жаһандық аралықты қарастырайық және кез келген ағын оның өлшемін динамикалық түрде кеңейте алады және басқа ағындар үшін қол жетімді ескі мазмұнды сақтай алады.

Іске асыру 1 (MSB GC нұсқасы):

int*   g_buf = 0;
size_t g_current_buf_size = 1024;

void InitializeGlobalBuffer()
{
    g_buf = gcnew int[g_current_buf_size];
}

int GetValueFromGlobalBuffer(size_t index)
{
    return g_buf[index];
}

void EnlargeGlobalBufferSize(size_t new_size)
{
    if (new_size > g_current_buf_size)
    {
        auto tmp_buf = gcnew int[new_size];
        memcpy(tmp_buf, g_buf, g_current_buf_size * sizeof(int));       
        std::swap(tmp_buf, g_buf); 
    }   
}

Іске асыру 2 (RCB GC нұсқасы):

std::shared_ptr g_buf;
size_t g_current_buf_size = 1024;

std::shared_ptr NewBuffer(size_t size)
{
    return std::shared_ptr(new int[size], []( int *p ) { delete[] p; });
}

void InitializeGlobalBuffer()
{
    g_buf = NewBuffer(g_current_buf_size);
}

int GetValueFromGlobalBuffer(size_t index)
{
    return g_buf[index];
}

void EnlargeGlobalBufferSize(size_t new_size)
{
    if (new_size > g_current_buf_size)
    {
        auto tmp_buf = NewBuffer(new_size);
        memcpy(tmp_buf, g_buf, g_current_buf_size * sizeof(int));       
        std::swap(tmp_buf, g_buf); 

        //
       //Now tmp_buf owns the old g_buf, when tmp_buf is destructed,
       //the old g_buf will also be deleted. 
       //     
    }   
}

ЕСКЕРТПЕ:

std :: swap (tmp_buf, g_buf) деп аталғаннан кейін tmp_buf ескі g_buf иеленеді. tmp_buf жойылған кезде ескі g_buf де жойылады.

If another thread is calling GetValueFromGlobalBuffer(index); to fetch the value from the old g_buf, then A Race Hazard Will Occur!!!

Осылайша, іске асыру 2 орындалуы ретінде талғампаздықпен көрінеді, бірақ ол жұмыс істемейді!

Егер біз 2-ші жұмысын дұрыс орындағымыз келсе, біз құлыптау механизмінің қандай да бір түрін қосуымыз керек; онда ол тек баяу ғана емес, сонымен бірге жүзеге асудан кем талғампаз болады.

Қорытынды:

Қосымша нұсқа ретінде C ++ стандарттарына MSB GC қабылдау өте жақсы.

1
қосылды