2 Ekim 2019 Çarşamba

std::unique_ptr Sınıfı

Kullanım
#include <memory> yapmak gerekir

std::unique_ptr
Bu sınıf C++11 ile geliyor. new'lenen bir nesneyi sarmalar ve sahiplenir.

unique_ptr ve raw pointer
Açıklaması şöyle. unique_ptr bazı işlemlerde raw pointer kadar hızlıdır.
The claim that unique_ptr performs as well as a raw pointer after optimization mostly applies only to the basic operations on a single pointer, such as creation, dereferencing, assignment of a single pointer and deletion. Those operations are defined simply enough that an optimizing compiler can usually make the required transformations such that the resulting code is equivalent (or nearly so) in performance to the raw version.
unique_ptr Trivially Copyable Değildir
Açıklaması şöyle.
Now std::unique_ptr is not trivially copyable since indeed it fails several of the requirements such as having only trivial or deleted copy and move constructors.
unique_tr ve Deleter
Eğer template paremetresi olarak deleter vermezsek bir maliyeti olmaz. Açıklaması şöyle.
std::unique_ptr<T> is quite likely to be zero-overhead (with any sane standard-library implementation). std::unique_ptr<T, D>, for an arbitrary D, is not in general zero-overhead.
Deleter verilen ve verilmeyen kod şöyledir.
template<typename T, typename D, bool Empty = std::is_empty_v<D>>
class unique_ptr
{
    T* ptr;
    D d;

    // ... 
};

template<typename T, typename D>
class unique_ptr<T, D, true> : D
{
    T* ptr;

    // ...
};
Yukarıdaki kodda görünmüyor ancak eğer custom deleter sağlamazsak normalde std::default_delete metodu kullanılır.
template<class _ElementT, class _DeleterT = std::default_delete<_ElementT>>
class unique_ptr
{...};
Template Parametresi - array ile kullanmak
delete yerine delete[] kullanılması için tip'ten sonra [] koymak gerekir. Array of class şeklinde kullanmak için örnek:
unique_ptr<A[]> a(new A[5]);
Array of primitive ise şöyle kullanılır.
std::unique_ptr<int[]> arr(new int[5]); // will call delete[]
                   ↑↑
Template Parametresi - custom deleter
std::unique_ptr ve Custom Deleter yazısına taşıdım.

Constructor - default
Default constructor nesne içermeyen bir unique_ptr yaratır.
std::unique_ptr<Foo> a1();
std::unique_ptr<Foo> a2(nullptr);
Constructor - move
Sağdaki nesne null olur.
unique_ptr<int> p1 = ...;
unique_ptr<int> p2 = move(p1);
if ( p1 ) {...} //False
Constructor - kalıtım ile
std::unique_ptr ve Kalıtım yazısına taşıdım.

aliasing constructor metodu
Bu sınıfın std::shared_ptr gibi aliasing constructor metodu yoktur.

deleted copy constructor metodu
Sınıfın copy constructor metodu yoktur. Dolayısıyla bu sınıf kopyalanmaya çalışılırsa derleyici hata verir. Hata ".. can't be referenced. It is a deleted function" şeklindedir.

1. Hata örneği - Metoda parametre olarak geçmek
Örnekte unique_ptr bar() metoduna copy constructor kullanılarak parametre olarak geçilmeye çalışılıyor. Derleyici hata verir.
void bar(std::unique_ptr<int> p)
{
}

int main()
{
    unique_ptr<int> p = foo();
    bar(p); // error,
    bar(std::move(p)); // this is OK but don't use p
}
destructor metodu
Sınıfın destructor metodu yok. Dolayısıyla kalıtım kullanılılabilirse de dikkatli olmak lazım. Şöyle yaparız.
void ADeleter(A *ptr) {
  // custom deletion logic
}

class APtr : public std::unique_ptr<A, void(*)(A *ptr)> {
  APtr() : APtr(nullptr) {}
  APtr(A *ptr) : std::unique_ptr<A, void(*)(A *ptr)>(ptr, ADeleter) {}
};
get metodu
operator* ile aynı işlevi sağlar yani saklanılan nesneye erişim sağlar. Sadece pointer'ın dolu olduğundan eminsek kullanılmalıdır. Örnek:
std::unique_ptr<int> u1(new int(0));
std::cout<<u1.get()<< std::endl;
unique_ptr'nin içindeki nesneye erişim sağlanması yanlış bir tasarım değil. Bu sınıfın amacı pointer'ı kimin sileceğini belirlemek.

The point of using smart pointers is about controlling who deletes the object, not who observes the object. It's perfectly fine under the smart pointer paradigm to observe the object owned by a smart pointer through a non-smart pointer or reference. In fact, this is a fairly common pattern that a class returns a non-owning pointer or reference to memory that it owns.
operator bool
Nesnenin dolu olup olmadığını kontrol etmemizi sağlar.
std::unique_ptr<int> ptr(new int(42));
if (ptr) {...}
operator = metodu - rvalue
İmzası şöyle.
unique_ptr& operator=( unique_ptr&& r ) noexcept;
Şöyle yaparız.
std::make_unique<int>(1) = std::make_unique<int>(1);
operator []
Template parametresi dizi ise kullanılır. Sınıfımız şöyle tanımlanmış olsun.
std::unique_ptr<Foo[]> ptr;
Belirtilen elemana şöyle erişiriz.
return ptr[5]
Bu metod dizinin boyunu aşıp aşmadığımızı kontrol etmez!

operator *
Saklanan nesneye erişim sağlar. Sadece pointer'ın dolu olduğundan eminsek kullanılmalıdır.

operator T* - sağlanmıyor
Conversion operator hata yapamayı kolaylaştıracağı için sağlanmıyor. Sağlansaydı şu şekilde hata yapmak çok kolay olurdu.
unique_ptr<something> p;
...
delete p; // p is a smart pointer - probably not what you want.
operator <<
std::unique_ptr için << operatörü yok. Ama eklemek si de çok kolay.
#if __cplusplus <= 201600 // Some time in future
namespace std {
    template <class E, class T, class Y, class D>
    basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os,
                                     unique_ptr<Y, D> const& p) {
        return os << p.get();
    }
}
#endif
release metodu
Release metodu raw pointer'ı döndürür ve sahipliğini bırakır. Raw pointer silinmez. Şöyle bir nesnemiz olsun.
std::unique_ptr<Foo> p (new Foo ());
Bu nesnenin içindeki raw pointer şöyle serbest bırakılır.
Foo * f = p.release();
reset metodu
Nesnenin sahip olduğu raw pointer silinir.
p.reset();
Eğer yeni bir atama yapmak istersek şöyle yaparız. Açıklaması şöyle
4 Effects: Assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not equal to nullptr, calls get_deleter()(old_p). [ Note: The order of these operations is significant because the call to get_deleter() may destroy *this. — end note ]
Bu durumda strong exception safety için önce yeni pointer atanır. Daha sonra eski pointer silinir.
p.reset(new T(...));


Hiç yorum yok:

Yorum Gönder