19 Ocak 2016 Salı

Static Yerel (Local) Değişken

static local değişken metod ilk kez çağırıldığında ilklendirilir - non-trivial initialization
C++'ta bir nesnenin storage duration ve lifetime süreleri farklı şeylerdir. static local değişken için storage alanı uygulama ilk defa başlatılırken ayrılır.

Ancak ilklendirme yani lifetime'ın başlaması değişebilir. Eğer değişken trivial bir tipse tipse, hem storage hem lifetime uygulama açılırken başlatılabilir. Şöyle bir metodumuz olsun
{static int i = 0;}
i değişkenine 0 değeri en başta atanabilir. Metodun ilk kez çağrılmasını beklemeye gerek yoktur.

Eğer static local değişken constructor'a  sahip bir nesne ise, ilklendirme işlemi metod ilk kez çağrıldığında yapılır.Şöyle bir metodumuz olsun
void func1()
{
  static X i;
  ...
}
Bu metod ilk kez çağrıldığı zaman, X nesnesinin constructor metodu çağrılır.

static local değişken guard ile korunur
X nesnesi multi-threaded kod tarfından kullanılıyorsa, yaratılmasında problem olabilir. Bu yüzden derleyici bizim için X değişkeninden önce guard koyar.
void func1()
{
  static X i;
  static guard x_is_initialized;
    if ( __cxa_guard_acquire(x_is_initialized) ) {
        X::X();
        x_is_initialized = true;
        __cxa_guard_release(x_is_initialized);
    }
  ...
}
Gömülü bir platformda bir kez
Undefined reference to __cxa_guard_acquire
Undefined reference to __cxa_guard_release
hatasını bu yüzden almıştım.

static local değişken'in özyinelemeli kod kullanılması
Secure Coding için şöyle bir paragrah var.
Do not reenter a function during the initialization of a static variable declaration. If a function is reentered during the constant initialization of a static object inside that function, the behavior of the program is undefined. Infinite recursion is not required to trigger undefined behavior, the function need only recur once as part of the initialization.
Bu şu anlama geliyor. Static değişken kendini ilklendirmek için özyinelemeli kod kullanmamalı.
int foo(int i) {
  static int s = foo(2*i); // recursive call - undefined
  return i+1;
}
Böyle bir kod şu exception'a sebep olur.
terminate called after throwing an instance of '__gnu_cxx::recursive_init_error'
  what():  std::exception
static local değişken ve heap
Static local değişkeni heap'te yaratabiliriz.

class B {
  public:
   static const B* GetInstance() {
     static B* b = new B ();
     return b;
   }
};
Ancak uygulama sonlanırken önce static local değişken yok olacağı için heap'teki nesneyi silme şansımız olmayacaktır. Bu gibi durumlarda std::unique_ptr kullanmak iyi bir fikir.

class B {
  public:
   static const B* GetInstance() {
     static std::unique_ptr<B> b( new B() );
     return b.get();
   }
};

static local değişkenin yok edilmesi
static local değişkenlere program kapanırken dokunmamak gerekir.
If a function contains a block-scope object of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behavior if the flow of control passes through the definition of the previously destroyed block-scope object.

Aşağıdaki kod tanımsız iş yapar.
void theFunction()
{
  static std::unique_ptr<int> foo { new int(42) };
}

struct Creator
{
  Creator() { theFunction(); }
};


struct Destroyer
{
  ~Destroyer() { theFunction(); }
};

Destroyer d;
Creator c;

int main()
{}

Hiç yorum yok:

Yorum Gönder