Khubur

Bilinen üye
14 Eyl 2016
910
345
63
(35) İzmir
zeybek.games
Merhaba topluluk! Bu yazıda, standart C++ pointer("veya göstergeç")'lerin aksine Unreal Engine 4'ün sunduğu akıllı pointerlar sayesinde oyununuzda gerçek zamanlı çalışma sırasında size inanılmaz efektif çalışma imkanı kazandırır. Akıllı göstergeçler sayesinde belirli metodlara veya objelere daha hızlı erişimini oluşturup memory leaks("hafıza kaçışları")'nı önleyebiliriz. C++, shared_ptr sayesinde birden çok göstergeçlerimizi bir arada tutup bunlar hakkında işlemler yapabiliyorduk. TArray, TSet ve TMap gibi Unreal Engine'nin sunduğu güzel ve kolay imkanlardan birisi de bellek yönetimini garbage collection olmasına rağmen paylaşılan göstergeçler sayesinde objenin yıkıldığı("yok edildiği") zaman birlikte yok edilmesi veya birlikte işlem yapılma imkanını sağlıyor. Bu yazıyı bir yere kopyaladığını zaman adımı ("Ali Kubur") yazarsanız sevinirim.

(Eğer Ogre3D motorunda programlayıcı olarak çalıştıysanız bu konu sizin için hiç yabancı gelmeyecektir!)

<NOT>: Forumda herhangi bir C++ söz dizimi tanımlayıcısı olmadığı için PHP Code olarak gördüğünüz yerleri C++ Kodu olarak okumanız daha iyidir.

Eğer normal göstergeçleri ve paylaşılan göstergeçleri nasıl kullanacağınızı bilmiyorsanız, lütfen göz atın: 
Basit Göstergeç Anlatımı: https://www.programiz.com/cpp-programming/pointers
shared_ptr Kullanımı: http://en.cppreference.com/w/cpp/memory/shared_ptr
İkili Ağaç: http://www.cprogramming.com/tutorial/c/lesson18.html


Normal Göstergeçler(Normal Pointers):
 Unreal Engine'de göstergeç normalde alttaki gibi tanımlıyoruz. Herhalde bu oldukça hoş gözüküyor.
PHP:
 AActor* BenimAktorum;
 gibi basit tanımlamalarla Aktör sınıfın belirli bir işaretçi("gösterici") örneğini yarattık.

Unreal Akıllı Göstergeçler(Smart Pointers):
Basitçe, belirli göstergeçleri paylaşınca daha hızlı ve efektif şekilde bir obje yıkıldığında("veya yok edildiğinde") bellekteki yönetimi sağlamak amaçlıdır. Akıllı karakterler C++ dilindeki hafıza yönetimi ile neredeyse aynı özelliklere sahiptir. Paylaşılan göstergeçler oldukça hızlıdır. Boost ya da STL gibi kütüphanelerle çalışırken paylaşılan göstergeçler daha hızlı bir uygulama imkanı sağlar.

USPL Üç ana temel uygulamadan oluşur. 

[size=small]1. Paylaşılan Göstergeçler (TSharedPtr)
[size=small]2. Paylaşılan Referanslar (TSharedRef)
3. Zayıf Göstergeçler (TWeakPtr)  (Yardımcı sınıf ve yardımcı fonksiyonlar için çok kullanışlıdır. Bu şablon, [/b] C++0x sürümünden sonra standart kütüphanenin shared_ptr üzerine uygulanmıştır.)

Paylaşılan Göstergeçler (TSharedPtr):
TANIM: 
İzinsiz bir şekilde başka bir göstercinin işine karışmaz. Diğer göstergeçlerin üzerinde işlem yeteneği bulunan yetkili bir şablondur. Obje yıkıldığı zaman.Null değeri alabilir.

ÖZELLİKLERİ:
+ Ortak göstergeçlere sahip olunmasını sağlar örneğin bir vektörümüz ve bir aktörümüz var bunları paylaşılır olarak atayabilirsiniz.
+ Otomatik geçersiz kılma. Paylaşılan bir göstergeç yok olduğunda otomatik TSharedPtr halleder.
+ Döngüden çıkmak için zayıf referansları tanımlamak için kullanılıyor.
+ Programcılar için belirtili bir şekilde gözlem yapma seçeneği. Bu sayede yok olan bir değerin hafızasını hesaplayabiliyoruz.
+ Müdahaleci değil. Ancak yansıma("reflection") ile başka bir göstergeç için müdahale edilebilir.
+ İyi performans, ışık hızında çuv çuv.
+ Thread-Safe ( yani bilgisayardaki hesaplamalarda işlem sırası önceliği için güvenilir bir imkan ) 

TANIMLAMA VE YÜKLEME:

 NOT: Paylaşılan göstergeçleri tanımlarken daha önceden var olan bir obje üzerinde çalışmamız lazım. Ve paylaşım başlatılınca tekrardan tanımlanılamaz.

Kod:
// Boş bir paylaşılan göstergeç yaratılır
TSharedPtr<FTreeNode> BlaBlaBla;

// Yeni bir objeye paylaşılan bir göstergeç yaratılır.
TSharedPtr<FTreeNode> Node( new FTreeNode() );

İlk örnekte işe FTreeNode yaramayan bir paylaşılan göstergeç tanımlıyoruz.
İkinci örnekte ise yeni FTreeNode objesi paylaşılan göstergeç tarafından sahiplenildi. Node adında bir paylaşılan göstergeç yaptık. Paylaşım kapsamından çıktığı zaman, obje yıkılacak ("yok edilecek").

Bir paylaışlan göstergeci kopyaladığınız zaman belirtilen nesneye referansı eklenir.
Kod:
TSharedPtr<FTreeNode> BirBaskaReferans = Node;

Paylaşılan göstergeçler için Reset metodu ile tüm göstergeçler için null değeri atabiliriz.

Kod:
Node.Reset();
Node = null;

Erişmek ve de-referans etmek istiyorsak: 
Normal C++ göstergeçleri gibi düşünebiliriz.

Kod:
Node->ListChildren();
Node.Get()->ListChildren();
( *Node ).ListChildren();

Aynı şekilde karşılaştırılabilinir. Mesela ikisi de aynı objeyi gösteriyorsa.

Kod:
TSharedPtr<FTreeNode NodeA, NodeB;

if( NodeA == NodeB )
{
    ...
}

IsValid() metodu ile paylaşılan göstergeçlerin var olup olunmadığı kontrol edilebilir.


Kod:
if( Node.IsValid() )
{
    ...
}

// veya

if( Node.Get() != null ) // eğer göstergeçimiz boş değerine eşit değilse (yani varsa)
{
    ...
}

Dönüşüm:  MakeShareable() metodu sayesinde paylaşılan gösterçlerimizi belirli şekilde dönüşümü yapabiliriz. Diğer şekilde değişkeni değiştiremeyiz.
Kod:
TSharedPtr<float> Height = MakeShareable( new float( 45.0f ) );



[size=small][size=small]Paylaşılan Referanslar (TSharedRef):
TANIM: 
Boş "null" değeri alamaz.Akıllı göstergeçler gibi düşünebiliriz fakat paylaşılan referanstır. Herhangi bir şekilde işlem yeteneği bulunmaz. Göstergeçlere erişmek için daha güvenli imkan sağlar. Paylaşılan işaretçiler zaman her zaman vailddir. Bu yüzden isVaild metodu yoktur. Paylaşılan göstergeçler yerine paylaşılan referansların kullanılması daha çok tercih edilir.

ÖZELLİKLERİ:
+ Paylaşılan göstergeçler ile aynı özellikleri taşırlar fakat "null" değer alamazlar.

TANIMLAMA VE YÜKLEME:
Paylaşılan göstergeçte olduğu gibi geçerli bir nesne üzerine yükleme yapılır.

Kod:
// Düğüme yeni bir paylaşılan referans oluşturuyoruz yeni bir değer oluşturmalıyız.
TSharedRef<FTreeNode> NodeRef( new FTreeNode() );

Aşağıdaki çalışmayacaktır çünkü değerimiz boş ve geçerli bir nesne yaratmadık.

Kod:
TSharedRef<UBool> BosBoolDeger;            // Compile etmez çünkü null değerine sahip.

Aşağıdaki kullanım paylaşılan göstergeçler gibi kullanılabilinir.
Kod:
// Yeni bir paylaşılan referans düğümü yaratalım
TSharedRef<FTreeNode> NodeRef( new FTreeNode() );

NodeRef->ListChildren();
( *NodeRef ).ListChildren();
const FTreeNode& NodeVar = NodeRef.Get();

Paylaşılan referansların en büyük farkı null değeri atamayışımız!
Kod:
TSharedRef<FTreeNode> Node = null;      // Compile etmeyecek

Zayıf Göstergeçler (TWeakPtr):
TANIM: 
Zayıf göstergeç, bir nesnenin göstergeçini hafızaya depolar. Paylaşılan bir işaretçinin aksine zayıf işaretçi bir nesnenin yok edilmesini engellemez. Zayıf göstergeçler kimin yok ettiğine bakmaksızın, yok edildiği zaman otomatik olarak boşaltılır. Bu sayede farkından olmadan yok olan nesneler için bunu sizin önbelleğe almanızı sağlar. Zayıf işaretçiler beklemediğinizde boşalabilir ve referans döngülerini kırmak için zayıf işaretçiler kullanılabilir.

ÖZELLİKLERİ:
1. Paylaşılan işaretçiler ile aynı kaderi paylaşır. fakat bir şey dışında o da altta yazıyor.
2. Fakat önemli özelliği artık paylaşılan referans kalmayınca zayıf göstergeçin nesnesi otomatik olarak yıkılır.
3. Bir sınıfın içinde zayıf objeyi gördüğünüz zaman, bir göstergeçi objeden yakalıyor anlamında geliyor. yani objedeki göstergeci bu göstergeçe aktarıyoruz. 
4. Ve bu obje yok edildiği zaman bu işaretçi de yok oluyor.

TANIMLAMA VE YÜKLEME:


Kod:
// TSharedRef ile Yeni bir düğüm paylaştırıyoruz
TSharedRef<FTreeNode> NodeOwner( new FTreeNode() );

// Bu düğüme bir zayıf göstergeç yaratıyoruz
TWeakPtr<FTreenode> NodeObserver( NodeOwner );

Yok etmek için


Kod:
// Düğümü yok et
NodeOwner.Reset();


ERİŞMEK & DE-REFERANS ETME:

Kod:
// Zayıf gösterici aracılığyla düğüme erişme
TSharedPtr<TFreeNode> LockedObserver( NodeObserver.Lock() );

If( LockedObserver.IsValid() )
{
    //Object still exists, so it can be accessed
    LockedObserver->ListChildren();
}


Paylaşılan referansların ve göstergeçlerin yararları neler?:
Temiz Söz Dizimi: Aynı C++ göstergeçlerinde olduğu gibi normal bir şekilde göstergeçinizi kopyalama, referanslama ve paylaşılan göstergeçler ile karşılaştırma yapabilirsiniz.
Hafıza Sızıntılarını Önleme: Paylaşılan referanslar kalmadığı zaman kaynaklar otomatikmen silinir. Bu şekilde oyunumuzu hacklemeye çalışan bir kişi göstergeçlere uğrayamaz.
Zayıf Referanslama: Zayıf referanslama sayesinde bir obje yok edildiğinde onun durumunu güvenle kontrol edebilirsiniz.
Uygulama Emniyeti(Thread Safety): Birden fazla göstergeçlere geçiş yaparken güvenli durumlarda göstergeçler seçilir ("doğru thread seçilir")
Her yerde bulunma: Paylaşılan göstergeçleri sanal olarak her obje tipine uygulayabilirsiniz. Örneğin AActor ve APlayerController sınıfına uygulayabilirsin.
Çalışma Zamanı(Runtime) Emniyeti: Paylaşılan referanslar asla boş "null" dönmez. İstediğiniz zaman referansını çözebilirsiniz. Null dönmediği için, çalışma zamanında bir hamle saymaz.
Referans döngüsüzlüğü: Zayıf Göstergeçleri kullanarak referans döngüsünü kırabilirsiniz. 
Diğer göstergeçler ile danışması: Paylaşılan göstergeçler ile bir diğerine kolayca erişebiliyoruz. Çok efektif!
Performans: Bütün işlemler run-time esnasnnda yapılır.
Sağlam Özellikler: const, forward ve type-casting gibi uygulamalara imkan sağlıyor.
Hafıza: 64bitlik bir C++ göstergecinin iki katı büyüklüğündedir.