C++ Destructor & RAII & inline & friend

Destructor türkçe terim olarak sonlandırıcı kullanmak istiyorum.

Destructor nesnenin hayatı bitince çağırılan fonksiyondur.

Amaç Nedir?
Kullanılan kaynakların geri iade edilmesi.

Her sınıf için olmasada, bir nesne hayata geldiğinde iş yapabilmek için kaynak edinirler. Bu kaynaklar bir bellek alanı olabilir, bir port kullanılıyor olabilir vs. Ama nesnenin hayatı bittiğinde kaynakların geri verilmesi gerekiyor. (kaynaklardan biri heap ama başka kaynaklarda var tabi) kaynak olarak RESOURCE terimini kullanıcaz.

Her sınıfının bir destructor ının bulunması zorunlu (dilin kuralı)

Eğer sınıf bir kaynak edinmiyor ise destructor olacak mı?
Evet, destructor boş olabilir ama kesinlikle bulunmak zorundadır.

Eğer sınıfımızın geri vereceği bir kaynak yok ise derleyicide bizim için boş bir destructor yazabilir.

RAII(Resource Acque is Initialization)
Default kaynak edinme ilk değer verme yoluyla oluyor.

İsimler sınıf ismi ile aynı ise constructor ile destructor nasıl anlaşılacak?
Constructor ile karışmaması için destructor önüne ~ karakteri var

Nesnenin hayatı bittiği zaman çağırılır.

Destructor için neden ~ karakteri seçilmiş?
Tümleyen anlamında uydurulduğu söyleniyor, bir sınıfın constructor varsa ona tümleyen destructor vardır mantığında… Matematiksel notasyon olarak “not” gibi de düşünülebilir.

Private Destructor

Bir nesnenin hayatı ne zaman biter?
~> Bu konu nesnenin ömür kategorisine bağlıdır.
~> otomatik ömürlü nesneler scope sonlarına gelindiği zaman
~> static ömürlü nesneler için main bittiği zaman
~> dinamik ömürlü nesneler, delete operatörünün kullanılmasıyla

~> Destructor geri dönüş değeri yoktur
~> Destructor const olamaz
~> Eğer destructor yazmassam derleyici non-static, inline, public bir destructor yazar

~> Destructor overload edilemez
~> Default destructor diye birşey yok
~> Parametresiz olmak zorunda
~> Private olabilir ama private destructor client tarafından çağrılması sentaks hatası
~> Otomatik ömürlü nesneyi destructor etmek diye birşey yok

~> C++ ile C# ve Java dilleri arasında ki önemli fark, dile gömülü garbage collector yapısı olmaması

~> Garbage collector önemli bir run time maliyeti var

~> Constructor ismi ile çağırılması her zaman sentaks hatası iken destructorin ismi ile çağırılması hata değil. Yani destructor ismi ile çağırılabilir.

Ancak bir sınıfın destructor ismi ile çağırılması gereken tek bir senaryo var -> placement new operator

Placement new operator başka bir makale de anlatmaya çalışacağım. Şimdilik bir örnek

Placement New Operator
Constructor & Destructor
Constructor & Destructor
Static Keyword
Destructor Cagirilmiyor
delete keyword
Her nesne icin constructor cagirilacaktir
this

Örneklerden sonra tekrardan hatırlatmalar yapalım.

~> Constructor this göstericine sahip, this ile kullanılabilir.
~> Sınıfın özel fonksiyonları
constructor destructor
~> Constructor nesneyi hayata hazırlıyor, bellekte bir yere sahip olması bir storage olması ona bir nesne yapmaz. Bu nesnenin görevini yapabilmesi için bazı işlemleri gerçekleştirmesi gerekiyor. Yani bu nesnelere ilk değer vermekten başka birşey değil.
~> Nesne görevini yapabilmesi için kaynak edinmesi gerekiyor. Bu kaynakları nesneye bağlayan yapı constructor.

~> Dinamik ömürlüler için delete kullanmalıyız, delete kullanmazsak destructor çağırılmaz

~> Derleyicinin yazdığı destructor non-static inline public demiştik. Biraz bu inline konusundan bahsedelim.

inline bir keyword. Fonksiyon için 2 model var

  1. func(); external referans konusu. Derleyiciye bu fonksiyon için çağrı yapılırsa linker aradan çıkar, sen derle, kodu çağıran yere yolla
  2. Derleyici mümkünse bu fonksiyon inline ile aç diyebiliriz. Bunun dezavantajı, implemantasyon ile interface i birbirinden ayırmamış oluyoruz. Burada interfacete implemantasyon da var. Yani derleyicinin bu kodu görmesi lazım. Fonksiyonun kodu değişmemesi gerekiyor, çünkü değişirse cpp dosyalarıda tekrar recompile edilecek.

~> inline en çok constructor ve destructor oluyor. Amaç linkeri işin içine katmamak.
~> Kodu büyük olanların teknik olarak inline edilmesi zor.

C++ da bir sınıfın üye fonksiyonlarının sınıfın içinde tanımlanması aslında onları inline yapılmasıdır. inline ricasında bulunulması demek.

~> Global bir üye fonksiyonları inline yapabiliriz.
~> Yerel bir üye fonksiyonunu inline yapabiliriz, tabi her ikisi içinde de tanımlama başlık dosyası içinde yapılacak

example.h
inline int getmax(int a, int b);
inline int getmax(int a, int b)
{
return a > b ? a : b;
}

Başlık dosyasında hem fonksiyon bildirimi hemde fonksiyon tanımı var.
~> inline keywordu için tercih edilen yer, fonksiyon geri dönüş türünden önce tanımda yer alması daha sık karşılaşılır. Hem bildirim hem tanım varsa inline keywordu tanımda yer alması

~> inline bir implementasyon olarak görün, öyle düşünün

~> Bir fonksiyonu inline yaparak performans elde ederiz anlamına gelmez. Böyle bir beklenti de olabiliriz ama böyle birşey yok. Verimi etkileyen çok faktör var.

~> Kodu küçük, sıkça çağırılabilir mantığında bir performans artışı bekleyebilirsiniz ama verim artmışmı artmamışmı onu profiler ile bakıcaz.

~> Fonksiyon sınıf içinde bildirimini yap, sınıf dışında kodunu yaz

inline void Data::set(int a)
{
///////// yazımı daha çok tercih edilir
}

Hangi fonksiyonlar sınıf içinde inline tanımlanabilir?
~> Sınıfın hem static hem non-static fonksiyonları inline tanımlanabilir

static void func(){} ~> sınıf içinde

static olanlar class ile ilgili işlem yapar,
non-static olanlar nesne ile ilgili işlemler yapar,

inline hakkı global sınıflara özel bir yerkilendirme ile sınıfın private alanına erişim hakkı verebiliriz, (friend bildirimi)

class Kerem
{
friend int func(); // global isimli fonk bnm arkadaşım private erişim hakkı
}
friend keyword kullanimi
Sinifin tum fonksiyonlarina erisim yetkisi verme

inline tanım yeri neresidir?

~> cpp dosyası değil. header dosyasında olması gerek

~> ODR (One defination Role) bir kez tanımlama kuralı

~> Tanım atom atom aynı ise problem yok, ama uygulama pratiğinde yeri asla cpp değil

Static — Non-Static — Friend
Name Lookup

C deki struct ile C++ struct aynı değil. struct lar cpp de sınıf
~> Struct larda default bölüm public
~> Struct ında private bölümü olabilir ama azınlık senaryosu
~> Tüm üye fonksiyionlar ve değişkenleri public olan bir sınıfı struct olarak tanımlayabiliriz

class x{public:….}; yada struct x{};
C++11
Data myData{}; //default initialize
Data myData{1, 3}; // member whise initialize
Data myData(); // geri donus deger Data turunden myData fonksiyon
Data myData; // veri elemanlari 0a cekilmez cop deger olur
Data x{}; // 0, 0, 0 ~> 0 primitif ogeler 0 degerine cekilir
Data y; // 3, 1452, 0 ~> cop deger, primitif ogeler cop degeler

Neden böyle birşey var? Niye böyle birşey yapmışlar? 
~> Primitif öğeleri bu olmasada sıfır a çekebilirdi. Ama bunu bize bırakmışlar çünkü primitif üyeler bir dizide olabilirdi.

C dilinde olmayan dongu deyimi