C++ Memory Management 2

Kerim Fırat
3 min readFeb 12, 2022

Yazı serisinin “C++ Memory Management 1” için link

“new operator” Ve “operator new”

Üst seviye bir programlama dili kullanıyorsak “new operator” kavramını elbette biliyoruz. Ancak C++’da “new operator”’un yanısıra ayrıca “operator new” kavramı mevcuttur. Bu iki kavramın farklılıklarını görmek için aşağıda verilen örnek kod parçasına göz atalım.

Yukarıdaki kod parçasında kullanılan “new” anahtar kelimesi “new operator” kavramına aittir. Bu operatör diğer üst seviye programlama dillerinde olduğu gibi sabit bir operatördür ve davranışını değiştirmek söz konusu değildir. Ancak bu operatör iki yönlü çalışır.
Bunlar:

  • Belirtilen türde bir nesneyi tutmak için yeterli bellek ayırır.Yukarıdaki örnekte tür olarak “string” belirtilmiştir.
  • Bellekteki nesneyi başlatmak için bir “constructor” çağırır.

C++’da bellek ayırma ve nesne oluşturma birbirinden farklıdır ve farklı ele alınır,ancak birbirleriyle yakından ilişkilidir. Bu durumda “new” kullandığımızda hangisini yapıyoruz. Bir bellek ayırma işlemi mi,yoksa bir nesne oluşturma işlemi mi yapıyoruz. Elbette hem bellek hem de nesne oluşturma yapılmaktadır.Dolayısıyla “new” kullandığımızda,öncelikle bellek tahsis edilir ve bu bellekte bir nesne oluşturulur. Bir başka deyişle “new” operatörü her zaman bu iki şeyi birlikte yapar ve bu davranışını değiştiremeyiz.

Şayet bu işi devralmak istersek,bu iki görevle,yani bellek tahsisi ve nesne oluşturma ile manuel olarak ilgilenmeliyiz.Ancak bu işi devraldığımızda değiştirebileceğimiz tek şey,bir nesnenin belleğinin nasıl tahsis edildiğidir.
Dolayısıyla “new” operatörünü gerekli bellek tahsisini gerçekleştirmek için yeniden yazabilir veya overload-override yapabiliriz.
Bunun için aşağıdaki yapıyı yani “operator new” kavramını inceleyelim.

Kod yapısını incelediğimizde “void” türünde bir pointer döndürdüğünü görüyoruz.Yani henüz bir tür-tip belirtilmemiş.Dolayısıyla “size_t” ile belirtilen büyüklükte bir adresi işaret eden ham bir pointer döndürüyor.Ancak henüz başlatılmamış bir bellek alanı olduğunu altını çizelim.

Bu kavram nadir de olsa aşağıdaki gibi kullanılabilir. Bu kullanımı tercih ettiğimizde derleyiciye yardımcı olmuş oluruz.

Yukarıdaki kullanımda “operator new” bir string tutacak büyüklükte ham pointer döndürüyor. Bu kullanımın farklılığı,sadece tür için belirtilen sabit bir kapasitedir. Dolayısıyla iki kullanım arasında aslında bir fark yoktur.
Yani her durumda “operator new” yalnızca bellek ayırmaktan sorumludur ve bu sorumluluğu neticesiyle “malloc()”’a benzer.

Kısacası “operator new” bir ham bellek döndürür ve bu belleği alıp nesneye dönüştürmek “new” operatörün işidir. İşte bu yüzden aşağıdaki gibi bir dönüştürme işlemi yapılmaktadır. Yani “new operator” eşittir “new string()” veya “new Xtür()”.
Örnek:

Bu noktada derleyici perspektifi ile bellek ayırma ve başlatma sürecine bakalım. Bir derleyici aşağıdaki kod parçasını gördüğünde neler yapacaktır.

Derleyici,yukarıda verilen kodu şu şekle getirecektir:

Yani string için ham bir bellek pointer’i alır.
Daha sonra bir constructor çağırarak bellekteki nesneyi başlatır:

Ve aşağıdaki kod ile yeni nesneye işaret edilir:

NOT: “static_cast” bir dönüştürme kavramıdır. C++’da birden fazla casting kavramı mevcuttur. static_cast ve diğer casting kavramlarına ve bu kavramların memory management üzerindeki kullanımlarına kapsamlı olarak ileriki yazılarımda değineceğiz.

Dinamik olarak ayrılmış bir nesneyi silmek için “delete” komutu çağrılır.
Örnek:

delete ptr;

Bir silme işlemi sırasında iki şey olur.

  • İlk olarak “ptr”’ın,yani delete’den sonra belirtilen nesne pointer’i üzerinde uygun destructor çalıştırılır.
  • Nesne tarafından kullanılan bellek bir “operator delete” işlevi çağrılarak serbest bırakılır

NOT: C++’da “operator” kavramı çok geniş bir çerçevede kullanılır.
Dikkat edilecek husus ise,”operator new” ve “operator delete” işlevleri diğer operatör işlevlerinin(“operator=”,.. gibi) aksine,”new” ve “delete”’i overload etmez.

“operator new” Ve “operator delete” Overload

Oluşturma ve silme işlemleri için kullanılan “operator new” ve
operator delete”,yalnızca tek nesneler için geçerli olduğunu unutmayalım.
Dizi-Array için bellek ayırma işlemi “operator new[]” ile, ve belleği silme-serbest bırakma işlemi “operator delete[]” ile yapılır.
Ayrıca STL container’lar,yine ilgili container’ların bellek tahsisat nesneleri tarafından yönetilir. Yani “new” ve “delete” komutlarına doğrudan bağlı değildir. Bunun sebebi,ilgili container’ların dinamikliği ve buna bağlı bellek yönetimidir.

Aşağıda nesne ve dizi-array’lar için “operator new” ve “operator delete” fonksiyonlarına yer verilmiştir.

Bu fonksiyonların kullanımını gösteren bir örnek aşağıda yer almaktadır.
Örnek:

Output:
constructions (1): *
constructions (2): *****
constructions (3): ***************

KAYNAKLAR:
https://www.cplusplus.com/
https://en.cppreference.com/w/
https://www.kernel.org/doc/html/latest/admin-guide/mm/index.html
https://www.bogotobogo.com/
https://openjdk.java.net/groups/hotspot/docs/StorageManagement.html

-end of

--

--

Kerim Fırat

Senior C++,Android Platform(AOSP,AAOS) Developer,Performance Architect,Open Source Contributor | Turkey Java User Group Vice Chairman | Author