Neden herşey C işaretçileri kullanmak için değil mi ?
Ben bazı sınıf tanımlamak varsayalım:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
}
Yaz o zaman bazı kod kullanıyor. Neden aşağıdaki yapayım?
Pixel p;
p.x = 2;
p.y = 5;
Ben her zaman yazmak Java bir dünyadan geliyor:
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
Bunlar temelde aynı şey, değil mi? Diğer bir deyişle, yığın yığın iken, daha sonra silmek zorunda kalacağım. İkisi arasında herhangi bir temel fark var mı? Neden diğer üzerinden bir tercih etmeliyim?
CEVAP
Evet, bir yığın, yığın üzerinde başka bir şey değildir. İki önemli fark vardır:
- Birincisi, açık, ve daha önemlisi: Yığın ayırma yavaş. Yığın ayırma hızlıdır.
- İkinci ve çok daha önemli. RAII. Yığın ayrılan sürümü otomatik olarak temizlenir çünküyararlı. Kendi yıkıcı herhangi bir kaynak sınıfı tarafından tahsis temizlenmek garanti sağlayan otomatik olarak adlandırılır. Bu C, bellek sızıntıları önlemek nasıl essentialy . Asla
delete
kendini arıyor, yığın ayırmadelete
dahili çağrı, nesneler, typicaly onların yıkıcı sarma yerine onları kaçının. Eğer elle tüm ayırmalarını izlemek ve doğru zamandadelete
aramak için çalışırsanız, kod 100 satır başına en az bir bellek sızıntısı olacak, garanti ediyorum.
Küçük bir örnek olarak, bu kodu göz önünde bulundurun:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
};
void foo() {
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
bar();
delete p;
}
Oldukça masum kodu, değil mi? Bir piksel oluşturmak, sonra da alakasız bir işlevi diyoruz, ve sonra piksel sileriz. Bir bellek sızıntısı var mı?
Ve cevap "muhtemelen". Eğer bar
bir özel durum oluşturursa ne olur? delete
hiçbir zaman çağrılır, piksel asla silinmez, ve biz bellek sızıntısı. Şimdi şunu bir düşünün:
void foo() {
Pixel p;
p.x = 2;
p.y = 5;
bar();
}
Bu bellek sızıntısı olmayacak. Elbette bu basit durumda, her şey yığında alıyor temizlenmiş otomatik olarak, ama bile Pixel
sınıf vardı yapılmış bir dinamik ayırma içten, olmaz sızıntısı ya. Pixel
sınıfı sadece silen bir yıkıcı verilecekti, ve bu yıkıcı foo
işlevi gidiyoruz nasıl olursa olsun deniyor. Eğer bar
bir istisna attı çünkü çıkarsak bile. Biraz yapmacık aşağıdaki örnek bunu gösterir:
class Pixel {
public:
Pixel(){ x=new int(0); y=new int(0);};
int* x;
int* y;
~Pixel() {
delete x;
delete y;
}
};
void foo() {
Pixel p;
*p.x = 2;
*p.y = 5;
bar();
}
Piksel sınıfı içerden bazı yığın bellek ayırır, ama onun yıkıcı bu yüzden temizlik ilgilenirkullanaraksınıf, bu konuda endişelenmenize gerek yok. (Muhtemelen son örnek burada genel prensip göstermek için çok basitleştirilmiş olduğunu söylemeliyim. Eğer gerçekten bu sınıfı kullanacak olursak, birkaç olası hataları da içerir. Eğer y ayırma başarısız olursa, x hiçbir zaman serbest olur, ve eğer Piksel kopyalanmasını, biz her iki örnek de aynı verileri silmek için çalışıyor. Alın son örnek burada inanmayarak. -Dünya gerçek kod biraz karmaşıktır, ama genel bir fikir) gösterir
Tabii ki aynı tekniği bellek ayırmalarını dışındaki kaynaklara uzatılabilir. Örneğin dosya veya veritabanı bağlantıları kullanın sonra kapalı olduğunu, ya da bir iş parçacığı kod için eşitleme kilitleri serbest bırakılır güvence altına almak için kullanılabilir.
Neden her şey için HTTPS kullanmak değ...
Neden web uygulamaları için C kullanma...
Neden varlıklar/iş nesneleri için bağı...
Neden Apple ARK altında singleton dese...
Neden diğerleri üzerinde bazı platform...