14 Temmuz 2017 Cuma

new operator için üretilen kod

Giriş
"new operator" ve "operator new" farklı şeylerdir. Ve bence çok kötü bir isimlendirme yapılmış.

"operator new" aynı C'deki malloc gibi raw bellek alanı döndürür. Şöyle yaparız
char *x = static_cast<char *>(operator new(100));//malloc ile aynıdır
"new operator" ise C++ dilindeki bir anahtar kelimedir. Bu anahtar kelimeyi gören derleyici kod üretir. Şöyle yaparız
my_class *x = new my_class(0);
Bu yüzden "new operator" için 3 tane overload vardır.

new operator için üretilen kod
Not : Bu yazıda nesnemiz için user defined new operator olmadığını etmediğini farz ettim.

Kodlarken genellikle new T() şeklinde bir satır yazıp geçeriz. Arka planda neler döndüğüne pek dikkat etmeyiz. Aslında new T() kodunun çalışması için arka planda derleyici bizim için kod üretmektedir. Bu kod iki ana esasa dayanır.


1. Global operator new
Yaratmak istediğimiz nesne için heap'ten alan almak gerekir. Bunun için derleyici önce
T *p = ::operator new(sizeof(T)); // allocate memory for a T
çağrısı ile aynı malloc'taki gibi bellek alanı ayıran kod parçası ayrılır.

2. Contructor Çağrısı
Daha sonra da T nesnesinin constructor metodunu çağıran kod parçasını üretiyor.
Bu kod ise şuna benziyor.
Not : Aslında aşağıdaki kod placement new kodudur fakat kavramı göstermesi için almakta mahzur görmedim.
new (p) T; // construct a T into the allocated memory

3. Cast
Ayrılan bellek alanı istediğimiz nesne tipine cast edilerek bize verilir. Bu iş için kod üretilmiyor ancak mantıksa olarak işlemin bir parçası olduğu için eklemek istedim.

Sonuç
new T() çağrısı, global operator new - yani ::new()'den  -  farklıdır !

Global operator new ile derleyicinin ürettiği kodun farkını gösteren örnek aşağıda.
// Allocates space for a T, and calls T's constructor,
// or calls a user-defined overload of new.
//
T* v = new T;

// Allocates space for N instances of T, and calls T's 
// constructor on each, or calls a user-defined overload
// of new[]
//
T* v = new T[N];

// Simply returns a raw byte array of `sizeof(T)` bytes.
// No constructor is invoked.
//
void* v = ::operator new(sizeof(T));
new operator İçin Üretilen Kod
Şuna benzer.
template <typename T, typename... Ts>
T* library_new(Ts&&... xs)
{
  auto* ptr = /* request enough memory for `T` from OS */;
  new (ptr) T(std::forward<Ts>(xs)...);
  return ptr;
}

template <typename T>
void library_delete(T* ptr)
{
  ptr->~T();
    /* reclaim memory for `T` from OS */
} 
Nesnenin Heap'te Yaratılmasını Önlemek
Bunun için sadece new operator'ünü saklamak yeterli.
private:
    void* operator new(size_t);          // standard new
    void* operator new(size_t, void*);   // placement new
    void* operator new[](size_t);        // array new
    void* operator new[](size_t, void*); // placement array new
Aynı zamanda delete operatürünü de engellemek gerekebilir. Ama yazmadım.

Hiç yorum yok:

Yorum Gönder