it-swarm.asia

C ++ ile kodlama yaparken neden işaretçiler önerilmez?

C++ kullanırken işaretçiler kullanmamanın tavsiye edildiği bir yerden okudum. C++ kullanırken işaretçiler neden bu kadar kötü bir fikir. İşaretçileri kullanmaya alışkın olan C programcıları için, C++ 'da daha iyi alternatif ve yaklaşım nedir?

45
Joshua Partogi

Sanırım normal işaretçiler yerine akıllı işaretçiler kullanmanız gerektiği anlamına geliyor.

Bilgisayar biliminde akıllı işaretçi, otomatik çöp toplama veya sınır denetimi gibi ek özellikler sağlarken işaretçiyi simüle eden soyut bir veri türüdür. Bu ek özellikler, verimliliği korurken işaretçilerin yanlış kullanımından kaynaklanan hataları azaltmayı amaçlamaktadır. Akıllı işaretçiler genellikle bellek yönetimi amacıyla işaret ettikleri nesneleri izler.

İşaretçilerin kötüye kullanılması önemli bir hata kaynağıdır: işaretçiler kullanılarak yazılmış bir program tarafından yapılması gereken sabit ayırma, yeniden yerleştirme ve referanslama, bellek sızıntılarının oluşma riskini ortaya çıkarır. Akıllı işaretçiler, kaynak aktarımını otomatik hale getirerek bellek sızıntılarını önlemeye çalışır: bir nesneye ait işaretçi (veya bir dizi işaretçi içindeki son) yok edildiğinde, örneğin kapsam dışına çıktığı için sivri nesne de yok edilir.

C++ 'da vurgu çöp toplama ve bellek sızıntılarını önleme olacaktır (sadece iki isim). İşaretçiler dilin temel bir parçasıdır, bu yüzden bunları kullanmamak programların üç üçlüsü dışında neredeyse imkansızdır.

58
jmq

Polemiği yayınlayan kişi olduğum için “f * cking işaretçileri kullanma” Burada yorum yapmam gerektiğini hissediyorum.

Her şeyden önce, bir polemik olarak açık bir şekilde aşırı bir bakış açısını temsil eder. are (ham) işaretçilerin kesinlikle meşru kullanımları vardır. Ancak ben (ve birçok profesyonel C++ programcısı) bu vakaların son derece nadir olduğunu iddia ediyor. Ama gerçekten demek istediğimiz şu:

İlk:

Ham işaretçiler hiçbir durumda belleğe sahip olmamalıdır.

Burada, “kendi hafızası” esasen o işaretçide delete bir noktada çağrılır (ancak bundan daha geneldir). Bu ifade güvenli bir şekilde mutlak olarak alınabilir. sadece istisna, kendi akıllı işaretçinizi (veya diğer bellek yönetimi stratejisi). Ve orada bile normalde still düşük seviyede akıllı bir işaretçi kullanmalısınız.

Bunun mantığı oldukça basittir: kendi belleğine sahip ham işaretçiler bir hata kaynağı oluşturur. Ve bu hatalar mevcut yazılımda üretken: bellek sızıntıları ve çift silme - her ikisi de belirsiz kaynak sahipliğinin doğrudan bir sonucu (ancak ters yönde).

Bu sorun, neredeyse hiçbir ücret ödemeden, sadece ham işaretçiler yerine akıllı işaretçiler kullanılarak tamamen ortadan kaldırılabilir (uyarı: bu hala düşünmeyi gerektirir, elbette; paylaşılan işaretçiler can döngülere yol açar ve böylece bir kez bellek sızıntılarına tekrar - ancak bu kolayca önlenebilir).

İkinci:

C++ 'da işaretçilerin çoğu kullanımı gereksizdir.

Diğer dillerden farklı olarak, C++ değer semantiği için çok güçlü bir desteğe sahiptir ve sadece işaretçilerin indirilmesine gerek yoktur. Bu hemen gerçekleşmedi - tarihsel olarak, C++, C'de kolay nesne yönelimini kolaylaştırmak için icat edildi ve büyük ölçüde işaretçilerle birbirine bağlanan nesne grafikleri oluşturmaya dayanıyordu. Ancak modern C++ 'da, bu paradigma nadiren en iyi seçimdir ve modern C++ deyimlerinin genellikle işaretçilere ihtiyacı yoktur . İşaretçiler yerine değerler üzerinde çalışırlar.

Ne yazık ki, bu ileti hala C++ kullanıcı topluluğunun büyük kısımlarında yakalanmadı. Sonuç olarak, yazılan C++ kodunun çoğu, kodu karmaşık, yavaş ve hatalı/güvenilmez yapan gereksiz işaretçilerle doludur.

Modern C++ bilen biri için, nadiren herhangi bir işaretleyicilere (akıllı veya ham; yineleyici olarak kullanılması hariç) çok nadiren ihtiyaç duyduğunuz açıktır. Ortaya çıkan kod daha kısa, daha az karmaşık, daha okunabilir, genellikle daha verimli ve daha güvenilirdir.

97
Konrad Rudolph

Sadece ham bellek erişimi ve ayırma işlemlerinden sonra temizleme gibi işaretçiler kullanmanın daha mizaçlı yönlerini gizleyen soyutlamalar olduğu için. Akıllı işaretçiler, kap sınıfları ve RAII gibi tasarım desenleriyle ham işaretçiler kullanma ihtiyacı azalır. Bununla birlikte, herhangi bir soyutlama gibi, onların ötesine geçmeden önce nasıl çalıştıklarını anlamanız gerekir.

15
Ed S.

Nispeten basit olarak, C zihniyeti "Bir sorun mu var? Bir işaretçi kullanın" dır. Bunu C dizeleri, işlev işaretçileri, yineleyiciler olarak işaretçiler, işaretçi-işaretçi, geçersiz işaretçi - üye işaretçileri olan C++ 'ın ilk günlerinde bile görebilirsiniz.

Ancak C++ 'da bu görevlerin çoğu veya tümü için değerler kullanabilirsiniz. Bir işlev soyutlamasına mı ihtiyacınız var? std::function. İşlev olan bir değer. std::string? Bu bir değer, bu bir dize. Benzer yaklaşımları tüm C++ üzerinde görebilirsiniz. Bu, kodun hem insanlar hem de derleyiciler için analiz edilmesini kolaylaştırır.

11
DeadMG

Sebeplerden biri işaretçilerin çok geniş uygulanmasıdır. Kapsayıcıların üzerinde yineleme için, işleve geçerken büyük nesneleri kopyalamaktan, önemsiz olmayan yaşam süresi yönetiminden, bellekte rastgele yerlere erişimden vb. Kaçınmak için kullanılabilirler. derhal bağımsız olarak.

Kesin amaç için bir aracın seçilmesi, kodu daha basit ve niyeti daha görünür hale getirir - yinelemeler için yineleyiciler, yaşam süresi yönetimi için akıllı işaretçiler vb.

10
maxim1000

Zaten listelenen nedenlerin yanı sıra, açık bir şey var: daha iyi optimizasyonlar. Yumuşatma analizi, bir işaretçi aritmetiği karşısında çok karmaşıktır, ancak referanslar bir iyileştiriciyi işaret eder, bu nedenle yalnızca referanslar kullanılırsa çok daha derin bir yumuşatma analizi mümkündür.

3
SK-logic

@Jmquigley işaretçisi ve işaretçi aritmetiği tarafından belirtilen bellek sızıntısı riskinin yanı sıra sorunlu olarak değerlendirilebilir çünkü işaretçiler bellekte her yeri gösterebilir "hata bulmak zor" ve "güvenlik açıklarına" neden olur.

Bu yüzden C # ve Java'da neredeyse terkedildiler.

2
k3b