it-swarm-eu.dev

Proč se ukazatele nedoporučují při kódování pomocí C ++?

Někde jsem četl, že při použití C++ je doporučeno nepoužívat ukazatele. Proč jsou ukazatele tak špatný nápad, když používáte C++. Jaká je lepší alternativa a přístup pro programátory C, kteří jsou zvyklí používat ukazatele, v C++?

45
Joshua Partogi

Myslím, že znamenají, že byste měli používat inteligentní ukazatele místo běžných ukazatelů.

Ve vědě o počítačích je inteligentní ukazatel abstraktní datový typ, který simuluje ukazatel a zároveň poskytuje další funkce, jako je automatický sběr odpadu nebo kontrola mezí. Účelem těchto dalších funkcí je omezit chyby způsobené zneužitím ukazatelů při zachování účinnosti. Inteligentní ukazatele obvykle sledují objekty, na které ukazují, za účelem správy paměti.

Zneužití ukazatelů je hlavním zdrojem chyb: konstantní alokace, deallokace a odkazování, které musí být provedeny programem napsaným pomocí ukazatelů, představuje riziko, že dojde k úniku paměti. Inteligentní ukazatele se pokoušejí zabránit úniku paměti automatizováním automatického přidělování prostředků: když je ukazatel (nebo poslední v řadě ukazatelů) na objekt zničen, například proto, že je mimo rozsah, je zničen i špičatý objekt.

V C++ by byl kladen důraz na sběr odpadu a zabránění úniku paměti (abychom jmenovali alespoň dvě). Ukazatele jsou základní součástí jazyka, takže jejich použití je do značné míry nemožné, s výjimkou nejvzácnějších programů.

58
jmq

Protože já jsem ten, kdo publikoval polemiku „Nepoužívejte f * cking ukazatele“ Mám pocit, že bych zde měl komentovat.

Zaprvé, jako polemika to zjevně představuje extrémní hledisko. Tam are rozhodně legitimní použití (surových) ukazatelů. Ale já (a mnoho profesionálních C++ programátorů) tvrdím, že tyto případy jsou mimořádně vzácné. Co však máme na mysli, je následující:

Za prvé:

Nezpracované ukazatele nesmí za žádných okolností vlastnit paměť.

Zde „vlastní paměť“ v podstatě znamená, že v určitém okamžiku je na tomto ukazateli vyvoláno delete (ale je obecnější než to). Toto tvrzení lze bezpečně považovat za absolutní. Výjimka pouze je při implementaci vlastního inteligentního ukazatele (nebo jiného strategie správy paměti). A i tam byste měli běžně stále používat inteligentní ukazatel na nízké úrovni.

Důvod je poměrně jednoduchý: hrubé ukazatele, které vlastní paměť, představují zdroj chyb. A tyto chyby jsou ve stávajícím softwaru plodné: úniky paměti a dvojité vymazání - oba jsou přímým důsledkem nejasného vlastnictví zdrojů (ale jdou opačným směrem).

Tento problém lze zcela eliminovat, prakticky bez nákladů, pouhým použitím inteligentních ukazatelů namísto surových ukazatelů (upozornění: to stále vyžaduje myšlení, samozřejmě; sdílené ukazatele mohou vedou k cyklům, a tedy jednou opět k úniku paměti - ale to se dá snadno vyhnout).

Druhý:

Většina použití ukazatelů v C++ je zbytečná.

Na rozdíl od jiných jazyků má C++ velmi silnou podporu hodnotové sémantiky a jednoduše nepotřebuje směrování ukazatelů. To nebylo okamžitě realizováno - historicky byl C++ vynalezen tak, aby usnadňoval snadnou orientaci objektů v C, a spoléhal se těžce na konstrukci objektových grafů, které byly propojeny ukazateli. Ale v moderním C++ je toto paradigma zřídka nejlepší volbou a moderní idiomy C++ často nepotřebují ukazatele . Fungují spíše na hodnoty než na ukazatelích.

Tato zpráva bohužel stále nebyla zachycena ve velkých částech uživatelské komunity C++. Výsledkem je, že většina napsaného kódu C++ je stále plná zbytečných ukazatelů, díky nimž je kód složitý, pomalý a chybný/nespolehlivý.

Pro někoho, kdo zná moderní C++, je jasné, že velmi zřídka potřebujete ukazatele libovolné ukazatele (chytré nebo syrové; s výjimkou použití jako iterátory). Výsledný kód je kratší, méně složitý, čitelnější, často účinnější a spolehlivější.

97
Konrad Rudolph

Jednoduše proto, že máte k dispozici abstrakce, které skrývají temperamentnější aspekty používání ukazatelů, jako je přístup k nezpracované paměti a vyčištění po přidělování. U inteligentních ukazatelů, tříd kontejnerů a návrhových vzorů, jako je RAII, je potřeba použití surových ukazatelů snížena. To znamená, že stejně jako jakákoli abstrakce byste měli pochopit, jak vlastně fungují, než se přesunou za ně.

15
Ed S.

Relativně jednoduše, mentalita C je „Mám problém? Použijte ukazatel“. Můžete to vidět v řetězcích C, funkčních ukazatelích, ukazatelích jako iterátorech, ukazatelech na ukazatele, ukazatele na neplatné, dokonce i v prvních dnech C++ s ukazateli členů.

Ale v C++ můžete použít hodnoty pro mnoho nebo všechny tyto úkoly. Potřebujete funkční abstrakci? std::function. Je to hodnota, která je funkcí. std::string? Je to hodnota, to je řetězec. Podobné přístupy můžete vidět po celé C++. To usnadňuje analýzu kódu jak pro člověka, tak pro kompilátory.

11
DeadMG

Jedním z důvodů je příliš široká aplikace ukazatelů. Mohou být použity pro iteraci nad kontejnery, pro zamezení kopírování velkých objektů při přechodu do funkce, netriviální správu životnosti, přístup k náhodným místům v paměti atd. A jakmile je použijete pro jeden účel, další jejich funkce budou k dispozici okamžitě nezávisle na záměru.

Výběrem nástroje pro přesný účel je kód jednodušší a lépe viditelný - iterátory pro iterace, inteligentní ukazatele pro správu v reálném čase atd.

10
maxim1000

Kromě výše uvedených důvodů je tu ještě jeden zjevný: lepší optimalizace. Aliasingová analýza je příliš komplikovaná, pokud jde o aritmetiku ukazatele, zatímco odkazy naznačují optimalizátor, takže pokud jsou použity pouze odkazy, je možné provést mnohem hlubší aliasingovou analýzu.

3
SK-logic

Kromě rizika úniku paměti uvedeného ukazatelem @jmquigley a aritmetika ukazatele lze považovat za problematickou, protože kazatele mohou ukazovat všude v paměti způsobující „obtížné nalezení chyb“ a „bezpečnostní zranitelnosti“.

Proto byli téměř opuštěni v C # a Java.

2
k3b