C++ Memory Management 3

Kerim Fırat
3 min readFeb 20, 2022

Serinin önceki yazıları için:

C++ Memory Management 1 link
C++ Memory Management 2 link

“New” Ve “Delete”

Dinamik olarak bir nesne oluşturmak için “new” kullandığımızda,önceki bölümde de değindiğimiz gibi iki şey-aşama oluşur. Bunlardan ilki bellek tahsisinin yapılmasıdır. İkincisi ise,tahsis edilen bellek için bir veya birden fazla constructor çağrılmasıdır. Aynı şekilde “delete” kullanıldığında da benzer iki şey-aşama oluşur.Bunlardan ilki sahip olunan bellek için bir veya birden fazla destructor çağrılmasıdır. İkincisi ise “operator delete”’in çağrılmasıdır.

Bu noktada aklımıza “delete” ile ilgili şu soru gelebilir: Neden birden fazla destructor çağrılıyor?
Cevap: Bir bellekte birden fazla nesne bulunabilir. Bu durumda “delete” komutu her nesne için bir destructor çağıracaktır. Dolayısıyla ilgili bellekte kaç adet nesne oluşturulursa o adet kadar constructor ve nihayetinde yine o adet kadar destructor çağrılır.

Aşağıdaki örneği inceleyerek devam edelim.

Bu örnekte “ptrString” tek nesne olarak oluşturuluyor. Ancak “ptrStringArr” için aynı şeyi söyleyemeyiz. Dizi-Array oluşturma durumunda “new” komutu tek nesne oluşturma durumundan biraz farklı davranır. Çünkü dizi oluşturma “operator new” ile değil,bunun yerine “operator new[]” kullanır.
Ayrıca dizi oluşturulduğunda,ilgili bellekte birden fazla nesnenin yer alacağını artık biliyoruz. Dolayısıyla yukarıda değindiğimiz birden fazla constructor ve destructor durumlarının oluşması açığa kavuşmuştur.
Ancak sürecin devamını incelemekte fayda vardır. Dolayısıyla dizi nesneleri oluşturma ve silme işlemine biraz daha yakından bakalım.

Örnek:

Diziler için,dizideki her nesne bir constructor oluşturulmasına tekabül eder. Dolayısıyla yukarıdaki örnek dizi için 44 adet constructor çağrılacaktır.
Daha açık bir şekilde söylemek gerekirse:
operator new[]” çağrılarak dizi boyutu kadar bellek oluşturulur ve ardından her dizi öğesi için bir constructor çağrılır. Burada söz konusu bir “string” veri tipidir.
Aynı şekilde bir dizi silme operatörü kullanıldığında,her dizi öğesi için bir destructor çağrılır ve ardından ilgili bellek serbest bırakılır.
Örnek silme işlemi:

Konuya başlarken verilen ilk örnekte tekli nesne ve dizi silme işlemine yönelik kod parçası verilmişti. Buna göre iki tür “delete” vardır.

1.”delete” -”new” tek bir nesne için tahsis edilen belleği siler.
2.”delete[]” -”new” ile dizi için tahsis edilen belleği siler.
Dikkat: Diziler birden fazla nesne içerir.

Aşağıdaki örnekte “delete” ve “delete[]” kullanımı gösteriliyor.
Örnek:

Output

Program çıktısına baktığımızda ilk olarak tek nesne oluşturuluyor ve ilgili nesne siliniyor. Nesne tekli olduğu için bir kez constructor ve bir kez de destructor çağrılıyor.
Ancak dizi oluşturma süreci farklı olduğunu görüyoruz. Dizi boyutu 5 olarak belirlenmiştir. Dolayısıyla dizi boyutu kadar contructor ve silme işlemi sürecinde ise yine dizi boyutu kadar destructor çağrılıyor.
Peki,programcı unutarak veya bilmeyerek dizi silme işlemini aşağıdaki gibi yaparsa ne olur.
Örnek:

Bu örnekte “delete[]” yerine “delete” kullanılmıştır. Bu örneğin çıktısına bakalım:

default constructor
default constructor
default constructor
default constructor
default constructor
destructor data:0

Görüldüğü gibi dizi boyutu kadar nesne oluşturulmuş ancak silme işlemi,yani belleği serbest bırakma, sadece ve sadece tek bir nesne için yapıldığı görülüyor. Diğer nesneler için bellek işgali devam etmektedir. Elbette istenmeyen bir durumdur ve bellek yönetiminin en temel konusudur.

Böyle bir durum yaşandığında,sadece bellek işgali olmaz.Bunun da ötesinde,bellek bozulması meydana gelebilir.Çünkü derleyiciler bu gibi durumlarda faklılık gösterebilir. Örneğin yukarıdaki program çıktısında, “delete myObjArr” komutu dizinin ilk elemanı için destructor çağırmıştır.
Yani dizinin ilk elemanına ait nesneyi temizlemiştir.Ancak derleyicilere bağlı olarak “new” ve “new[]” bellek ayırma-tahsis şemaları birbirinden farklılık gösterebilir. Bu nedenle bellek bozulması meydana gelebilir.

Dizilerle çalışırken bellek yönetimi konusu daha da karmaşık hale gelebilir.
Örneğin pointer(*) olarak oluşturduğumuz bir diziyi silerken,yukarıdaki gibi silme işlemi yerine farklı bir yaklaşım gerekir.
Aşağıdaki örneği inceleyelim.

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