Yükleniyor...

Smart Pointer’lara Giriş

unique_ptr, shared_ptr ve weak_ptr ile güvenli yaşam döngüsü yönetimine giriş.

C++’ta dinamik bellek yönetimi geleneksel olarak new ve delete ile yapılır. Ancak manuel bellek yönetimi; sızıntılar, çifte serbest bırakma veya asılı pointer (dangling pointer) hatalarına yol açabilir. Modern C++ (C++11 ve sonrası), bu sorunları çözmek için akıllı pointer (smart pointer) kavramını getirmiştir. Smart pointer’lar, bellek yönetimini otomatik hale getirir ve hataları büyük oranda ortadan kaldırır.


1. Smart Pointer Nedir?

Smart pointer, bir nesnenin ömrünü yöneten özel bir C++ sınıfıdır. Normal pointer gibi davranır ancak nesnenin yaşam döngüsünü (oluşturma ve yok etme) otomatik kontrol eder. Bu sayede bellek sızıntıları önlenir.


#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> ptr = make_unique<int>(42);
    cout << *ptr << endl; // 42
}

unique_ptr, shared_ptr ve weak_ptr olmak üzere üç temel smart pointer türü vardır. Hepsi <memory> başlık dosyasında bulunur.


2. unique_ptr

std::unique_ptr, sahipliği yalnızca bir nesnede bulunan pointer’dır. Aynı anda yalnızca bir unique_ptr belirli bir nesneye sahip olabilir. Kopyalanamaz, ancak taşınabilir (std::move() ile).


#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> p1 = make_unique<int>(10);
    cout << *p1 << endl;

    // unique_ptr kopyalanamaz:
    // unique_ptr<int> p2 = p1; // HATA!

    // Ancak taşınabilir:
    unique_ptr<int> p2 = move(p1);
    cout << *p2 << endl;
}

Avantajları:

Dezavantajı: unique_ptr kopyalanamaz, bu yüzden paylaşım gereken durumlarda uygun değildir.


3. shared_ptr

std::shared_ptr, bir nesneye birden fazla pointer’ın sahip olmasına izin verir. Nesnenin ömrü, ona sahip olan pointer sayısına (reference count) bağlıdır. Son shared_ptr yok edildiğinde nesne otomatik olarak silinir.


#include <iostream>
#include <memory>
using namespace std;

int main() {
    shared_ptr<int> p1 = make_shared<int>(100);
    shared_ptr<int> p2 = p1; // Paylaşılan sahiplik

    cout << "p1: " << *p1 << ", p2: " << *p2 << endl;
    cout << "Kullanım sayısı: " << p1.use_count() << endl; // 2
}

Avantajları:

Dezavantajı:


4. weak_ptr

std::weak_ptr, shared_ptr tarafından yönetilen bir nesneye “zayıf” (non-owning) referanstır. weak_ptr nesnenin yaşam süresini uzatmaz, sadece varlığını gözlemlemeye yarar. Böylece döngüsel referans (circular reference) problemini önler.


#include <iostream>
#include <memory>
using namespace std;

int main() {
    shared_ptr<int> sp = make_shared<int>(50);
    weak_ptr<int> wp = sp;

    cout << "Kullanım sayısı: " << sp.use_count() << endl;

    if (auto ptr = wp.lock()) {
        cout << "Değer: " << *ptr << endl;
    }
}

wp.lock() geçerli bir shared_ptr döndürür; eğer nesne silindiyse nullptr döner. Bu yöntem, güvenli erişim sağlar.


5. Döngüsel Referans Problemi (Circular Reference)

shared_ptr’lar birbirini referans ederse, her iki tarafın referans sayısı sıfıra düşmez ve bellek sızıntısı oluşur. Bu durum genellikle bağlı (linked) veri yapılarında ortaya çıkar.


#include <memory>
using namespace std;

struct Node {
    shared_ptr<Node> next;
    // HATA: Döngüsel referans!
};

int main() {
    shared_ptr<Node> n1 = make_shared<Node>();
    shared_ptr<Node> n2 = make_shared<Node>();
    n1->next = n2;
    n2->next = n1; // Sonsuz referans döngüsü
}

Bu durumda weak_ptr kullanmak gerekir:


struct Node {
    weak_ptr<Node> next; // Artık döngü oluşmaz
};

6. Smart Pointer’larla Fonksiyon Kullanımı

Smart pointer’lar, fonksiyonlara normal pointer gibi parametre olarak geçebilir. Ancak sahiplik modeline dikkat edilmelidir.


void Yazdir(shared_ptr<int> p) {
    cout << *p << endl;
}

int main() {
    auto ptr = make_shared<int>(77);
    Yazdir(ptr); // Güvenli paylaşım
}

Eğer sahiplik devredilmek isteniyorsa, unique_ptr parametresiyle std::move() kullanılmalıdır.


void Al(unique_ptr<int> p) {
    cout << *p << endl;
}

int main() {
    auto p = make_unique<int>(88);
    Al(move(p)); // p artık boş (nullptr)
}

7. Smart Pointer’ların Bellek Yönetimi Avantajları


8. Karşılaştırma Tablosu

Tür Sahiplik Kopyalama Referans Sayımı Kullanım Alanı
unique_ptr Tek Yasak Yok Tek sahipli nesneler
shared_ptr Paylaşımlı Serbest Var Birden fazla sahipli nesneler
weak_ptr Sahiplik yok Serbest Bağımlı Döngüsel referans önleme

9. TL;DR

  • unique_ptr → tek sahipli, kopyalanamaz, taşınabilir.
  • shared_ptr → referans sayımıyla paylaşımlı sahiplik.
  • weak_ptr → paylaşılan nesneyi izler ama sahip olmaz.
  • Smart pointer’lar bellek sızıntılarını büyük ölçüde önler.
  • Döngüsel referanslarda mutlaka weak_ptr kullanılmalıdır.
  • Tüm örnekler Visual Studio 2022 veya GCC 11+ derleyicilerinde çalıştırılabilir.

İlişkili Makaleler