SORU
30 HAZİRAN 2009, Salı


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
30 HAZİRAN 2009, Salı


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ırma delete 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 zamanda delete 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.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • joshsnice

    joshsnice

    28 Kasım 2006
  • Stanislav Petrov

    Stanislav Pe

    7 ŞUBAT 2009
  • Warner Bros. UK

    Warner Bros.

    6 HAZİRAN 2008