---
title: 'Öbekte Tekil Sahiplik'
source: 'https://academia.sh/tr/kurslar/sahiplik/obekte-tekil-sahiplik'
course: 'Sahiplik ve Bellek Modeli'
language: tr
updated: '2026-09-13T05:09:25+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Öbeğe alınan bir değerin taşınsa bile tek bir sahibi olduğunu koşturarak gösterir'
    - 'Bir kabın içindeki tekil değer ile listedeki değerlerin bitiş sırasını karşılaştırır'
    - 'Öbekte tekil sahipliğin kendine referans veren bir tipi mümkün kıldığını örnekler'
---

# Öbekte Tekil Sahiplik

Bir değerin öbekte yaşarken de tek bir sahibi kalabildiği, kabıyla birlikte biten bir değerin kabın kendi sırasına bağlı olduğu ve bu tekilliğin kendine referans veren bir tipi mümkün kıldığı ölçülüyor.

Yapılarda Referans Tutma dersi, bir yapının bir veriyi ya taşıdığını ya ödünç aldığını, iki
durumda da tek bir sahibin bulunduğunu ölçerek kapandı. Bu dersin sorusu tam o varsayımı hedef
alıyor: bir değerin sahibi birden çok olabilir mi? Yanıtın kendisi henüz gelmiyor — önce
sahiplik **sayısı** değil, sahip olunan değerin **nerede** durduğu değişiyor. Bu ara adım
gerekli, çünkü paylaşımlı sahipliğin nasıl ölçüleceğini anlamak için önce tek sahipli bir
değerin öbekte nasıl davrandığını bilmek gerekiyor. Ölçü ekseni değişmiyor: burada da bir
değerin nerede bittiği soruluyor, Eşzamanlılık kursundaki (M09/K03) gibi koşan bir birimin
nasıl duracağı değil.

Kursun açılış dersi, bir değerin yığıtta mı öbekte mi durduğunu M01/K01 ve M09/K05'in
üçüncü tekrarı olarak ele almıştı; bellek kuramı orada kapandı, burada yeniden açılmıyor.
Aynı derste dört sınıf kuruldu: bir değer kapsam sonunda, taşındığı yerde, açık bir
çağrıyla ya da bir kabıyla birlikte biter. Bu dersin sorduğu şey şu: bir değer öbekte
durduğunda, bu dört sınıftan hangisine giriyor ve sahiplik kuralı hâlâ aynı mı kalıyor?
`Box`, bir değeri öbeğe taşıyan ama sahiplik sayısını hiç değiştirmeyen bir kaptır — bu
dersin ölçtüğü ilk şey budur.

## Kap da Bir Sınıf, Ama İçindeki Tek

"Kabıyla birlikte" bitişi tek bir biçimde gelmiyor. Bir liste birden çok değeri aynı anda
taşır; `Box` ise tam olarak bir değeri taşır. İkisi de kap sınıfına girer, ikisinde de
içerik kapla birlikte biter, ama kabın kendi bitiş sırası aynı değildir.

Bu dersin ölçümü de kursun açılışında kurulan `Iz`/`defter` düzeneğini kullanıyor: her
`Iz` değeri bırakıldığında kendi adını deftere ekliyor, bunu sağlayan `Drop` uygulaması
burada yeniden yazılmıyor, kesiti alınıyor. Aşağıdaki koşum, aynı kapsam içinde üç öğeli
bir listeyle tek bir `Box` değerini bir arada tutuyor ve kapsam kapanırken defterin aldığı
sırayı basıyor.

**PS1.** — "öbekteki tekil değerin listeden önce bittiği" iddiası, aşağıdaki koşumun
`bitis sirasi` satırıyla doğrulanıyor: `obekteki-tekil` adı, listenin üç elemanından önce
geliyor.

```rust
// kap_siniflari.rs — kabiyla birlikte sinifi: liste ve obekteki tekil deger
use std::cell::RefCell;
use std::rc::Rc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    {
        let mut liste = Vec::new();
        liste.push(Iz::yeni("liste-1", &defter));
        liste.push(Iz::yeni("liste-2", &defter));
        liste.push(Iz::yeni("liste-3", &defter));
        let _obekteki = Box::new(Iz::yeni("obekteki-tekil", &defter));
        println!("kap dolu iken defter uzunlugu: {}", defter.borrow().len());
    }
    let kayit = defter.borrow();
    println!("bitis sirasi: {}", kayit.join(", "));
}
```

```
kap dolu iken defter uzunlugu: 0
bitis sirasi: obekteki-tekil, liste-1, liste-2, liste-3
```

Kapsam kapanırken bağlamalar en son bağlanandan başlayarak biter: `_obekteki`, `liste`den
sonra bağlandığı için ilk biten o oluyor. Ardından `liste` bitiyor, ama listenin kendi
içindeki üç `Iz` değeri **ekledikleri sırayla** bitiyor. Bağlamaların bitiş sırası ile bir
kabın içindeki elemanların bitiş sırası aynı kural değildir — biri bildirimin tersini,
öbürü ekleme sırasını izler; `Box` tek elemanlı bir kap olduğu için bu ikinci kural onda
görünmez, yalnızca birinci kural işler.

## Öbekte Durmak Kullanım Biçimini Değiştirmez

Bir değerin öbekte durması, o değere nasıl erişildiğini değiştirmiyor. Bir `Box` içindeki
yapının alanlarına ve yöntemlerine, sanki değer doğrudan orada duruyormuş gibi erişilir;
aradaki kabı açmak için ayrı bir adım yazılmaz.

```rust
// kutu_erisimi.rs — box uzerinden erisim, deger dogrudan oradaymis gibi calisir
struct Nokta {
    x: i32,
    y: i32,
}

fn main() {
    let nokta = Box::new(Nokta { x: 3, y: 4 });
    println!("x: {}, y: {}", nokta.x, nokta.y);
    let toplam = nokta.x + nokta.y;
    println!("toplam: {}", toplam);
}
```

```
x: 3, y: 4
toplam: 7
```

`nokta.x` ve `nokta.y` satırları, `nokta`nın tipi `Nokta` olsaydı da `Box<Nokta>` olsaydı
da aynı yazılır. Aşağıdaki koşum bunu doğrudan karşılaştırıyor: aynı `Nokta` değeri önce
öbeğe alınmadan, sonra öbeğe alınarak okunuyor.

```rust
// erisim_karsilastirmasi.rs — box'lu ve box'suz erisim ayni satirla yaziliyor
struct Nokta {
    x: i32,
    y: i32,
}

fn main() {
    let dogrudan = Nokta { x: 1, y: 2 };
    let obekteki = Box::new(Nokta { x: 1, y: 2 });
    println!("dogrudan: x={}, y={}", dogrudan.x, dogrudan.y);
    println!("obekteki: x={}, y={}", obekteki.x, obekteki.y);
}
```

```
dogrudan: x=1, y=2
obekteki: x=1, y=2
```

İki satır arasındaki tek fark değerin nasıl kurulduğu (`Nokta { ... }` ile
`Box::new(Nokta { ... })`); alan okuma satırları birbirinin aynısı. Öbekte durmak
yalnızca değerin **nerede** tutulduğunu belirler; değerin okunma ve kullanılma biçimini
değiştirmez. Bu, ilerleyen derslerde paylaşımlı kapların da sürdüreceği bir düzendir: kabın
türü ne olursa olsun, içindeki değere erişim hep aynı satırla yazılır.

## Öbeğe Almak Sahipliği Çoğaltmaz

Sahiplik ve Taşıma dersi, işleve taşınan, iç kapsama taşınan ve bir yapının alanına
taşınan değerin bitiş noktasını taşıdığını ama sayısını hiç değiştirmediğini ölçmüştü.
Aynı ilke, öbekteki bir değer için de geçerlidir: bir `Box` değeri kaç kez el
değiştirirse değiştirsin, taşıdığı `Iz` yalnızca **bir kez** biter.

Aşağıdaki koşum, tek bir `Box<Iz>` değerini iki ayrı işlev çağrısından geçiriyor ve son
sahibin elinde bırakıyor.

**PS2.** — "üç el değiştirmeden sonra bile tek bir bitiş kaydının oluştuğu" iddiası,
aşağıdaki koşumun `toplam kayit sayisi: 1` satırıyla doğrulanıyor.

```rust
// kutu_tasima.rs — box'a alinan bir degerin tasinmasi tek sahiplik sayisini degistirmiyor
use std::cell::RefCell;
use std::rc::Rc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn baska_kapsama(alinan: Box<Iz>) -> Box<Iz> {
    // Sahiplik burada devraliniyor ve ayni deger geri donduruluyor.
    alinan
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    {
        let ilk = Box::new(Iz::yeni("tek-sahip", &defter));
        let ikinci = baska_kapsama(ilk);
        let ucuncu = baska_kapsama(ikinci);
        println!("uc tasimadan sonra defter uzunlugu: {}", defter.borrow().len());
        println!("son sahip: {}", ucuncu.ad);
    }
    let kayit = defter.borrow();
    println!("toplam kayit sayisi: {}", kayit.len());
    println!("kayitlar: {}", kayit.join(", "));
}
```

```
uc tasimadan sonra defter uzunlugu: 0
son sahip: tek-sahip
toplam kayit sayisi: 1
kayitlar: tek-sahip
```

`ilk` adlı bağlama `baska_kapsama` işlevine taşınıyor, oradan `ikinci` adıyla geri
dönüyor, sonra yeniden aynı işleve taşınıp `ucuncu` adıyla dönüyor. Üç bağlama, üç ayrı
addır, ama hepsi aynı `Iz` değerinin farklı zamanlardaki tek sahibidir. `ucuncu` biterken
defter uzunluğunun sıfır olması, önceki iki taşımanın **hiçbirinin** bir bitiş
üretmediğini gösteriyor: yalnızca son sahibin kapsamı kapandığında bir kayıt açılıyor.
Defterde tek bir `tek-sahip` kaydı oluşması, öbeğe almanın sahiplik sayısını
**çoğaltmadığını** doğruluyor — taşıma yalnızca kimin sahip olduğunu güncelliyor, yeni bir
kayıt açmıyor.

Bu sonuç ilk bakışta beklenmedik gelmeyebilir, ama karşıt durumu düşünmek farkı netleştirir:
sahiplik çoğalsaydı, `baska_kapsama` her çağrıldığında defterde ayrı bir bitiş kaydı
oluşurdu ve toplam üç kayıt görülürdü. Sahiplik ve Taşıma dersinde yığıttaki bir değer için
kurulan "tek sahip" kuralı, değer öbeğe taşındığında da bozulmuyor; taşınan şey değerin
kendisi değil, yalnızca o değere sahip olma hakkıdır.

## Box da Açık Çağrıyla Erken Bitebilir

Öbekteki bir değer, her zaman kabının kapanmasını beklemek zorunda değildir. Ödünç Alma
dersinde açık bir `drop` çağrısının bir değerin ömrünü erken bitirdiği ölçülmüştü; aynı
çağrı bir `Box` üzerinde de çalışır. Bu, "kabıyla birlikte" ile "açık çağrıda" sınıfları
arasındaki farkın **tipten değil**, değerin nasıl bitirildiğinden geldiğini gösteriyor.

**PS3.** — "erken bırakılan değerin, kapsamda kalan değerden önce bittiği" iddiası,
aşağıdaki koşumun `bitis sirasi` satırıyla doğrulanıyor.

```rust
// erken_birakma.rs — bir box degeri acik cagriyla erkenden birakilabilir
use std::cell::RefCell;
use std::rc::Rc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    {
        let erken = Box::new(Iz::yeni("erken-birakilan", &defter));
        let kalan = Box::new(Iz::yeni("kapsamda-kalan", &defter));
        drop(erken);
        println!("acik cagridan sonra defter uzunlugu: {}", defter.borrow().len());
        println!("kalan hala okunabilir: {}", kalan.ad);
    }
    let kayit = defter.borrow();
    println!("bitis sirasi: {}", kayit.join(", "));
}
```

```
acik cagridan sonra defter uzunlugu: 1
kalan hala okunabilir: kapsamda-kalan
bitis sirasi: erken-birakilan, kapsamda-kalan
```

`erken` değeri, `kalan`dan önce bağlanmasına rağmen kapsam sonunu beklemeden bitiyor;
`kalan` ise sıradan kapsam sonu kuralına uyuyor. Aynı tip — `Box<Iz>` — iki farklı bitiş
sınıfına düşebiliyor; sınıfı belirleyen kabın türü değil, kaynakta o değere ne
yapıldığıdır.

Bu dersin üç ölçümü bir araya geldiğinde, bir `Box` değerinin kursun açılışında kurulan
dört sınıftan üçüne girebildiği görülüyor: kapsamı doğal biçimde kapanırsa kabıyla
birlikte biter (Kap da Bir Sınıf bölümü), bir işleve ya da başka bir bağlamaya taşınırsa
bitiş noktası da onunla taşınır (Öbeğe Almak bölümü), açık bir çağrıyla bırakılırsa açık
çağrıda biter (bu bölüm). Yalnız kapsam sonu sınıfına giremez, çünkü öbekteki bir değer
her zaman ya bir kabın içindedir ya da bir taşımanın konusudur — hiçbir zaman yığıttaki
sıradan bir bağlama gibi kendi başına durmaz.

## Özyinelemeli Bir Tip: Öbeğin Açtığı Kapı

M01/K03 Veri Yapıları dersi, bağlı liste ve ağaç gibi kendine referans veren yapıları
kavram olarak kurdu; bu ders o yapıyı yeniden öğretmiyor, yalnızca öbekte tekil
sahipliğin böyle bir tipi **mümkün kıldığını** ölçüyor.

Bir zincirin her halkasının kendi türünden bir sonraki halkayı doğrudan — bir kap
olmadan — taşıdığı bir tanım derleyici tarafından reddediliyor: her halka bir sonrakini
doğrudan içerdiğinde, tipin kendisinin ne kadar yer kaplayacağı hiçbir zaman belirlenmiş
sayılmıyor, çünkü halka sayısı kaynaktan sabit bir sınırla okunamıyor. Bu, bir işlevin
kendini çağırmasından farklı bir sorundur: işlev özyinelemesi çalışma zamanında adım adım
ilerler, ama bir tipin tanımı derleme zamanında tek seferde okunmak zorundadır — kendi
içinde sonsuza kadar açılan bir tanım bu okumayı bitiremez.

Kuralın en yalın hâli şöyle özetlenebilir: bir `Kayit` yapısının `sonraki` adlı alanına
doğrudan `Kayit` tipini yazan bir tanım hiçbir zaman kabul edilmez, çünkü `sonraki` yine
bir `Kayit`tir ve bu tanım kendi içinde asla kapanmaz. Aynı alana `Box<Kayit>` yazan bir
tanım kabul edilir, çünkü `Box` öbekte duran, kendisi sabit biçimli ayrı bir kaptır —
tanımın kendisi `Kayit`in içine doğrudan bir `Kayit` değil, sabit biçimli bir kabın
kendisini yerleştirir. Kabul edilen yazım, sonraki halkayı da tam olarak bu yolla taşıyor:
doğrudan değil bir `Box` üzerinden ve bu yüzden zincir istediği uzunlukta sürebiliyor.

**PS4.** — "zincirin bitiş sırasının kurulma sırasıyla aynı ilerlediği" iddiası, aşağıdaki
koşumun `bitis sirasi: halka-a, halka-b, halka-c` satırıyla doğrulanıyor — sıra,
bağlamaların bitişinde görülen tersine dönüşü izlemiyor.

```rust
// zincir.rs — box'un actigi kapi: kendini icinde barindiran bir tip
use std::cell::RefCell;
use std::rc::Rc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

enum Zincir {
    Bos,
    Dugum(Iz, Box<Zincir>),
}

fn uzunluk(z: &Zincir) -> usize {
    match z {
        Zincir::Bos => 0,
        Zincir::Dugum(iz, sonraki) => {
            println!("gezilen halka: {}", iz.ad);
            1 + uzunluk(sonraki)
        }
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    {
        let zincir = Zincir::Dugum(
            Iz::yeni("halka-a", &defter),
            Box::new(Zincir::Dugum(
                Iz::yeni("halka-b", &defter),
                Box::new(Zincir::Dugum(
                    Iz::yeni("halka-c", &defter),
                    Box::new(Zincir::Bos),
                )),
            )),
        );
        println!("zincir uzunlugu: {}", uzunluk(&zincir));
    }
    let kayit = defter.borrow();
    println!("bitis sirasi: {}", kayit.join(", "));
}
```

```
gezilen halka: halka-a
gezilen halka: halka-b
gezilen halka: halka-c
zincir uzunlugu: 3
bitis sirasi: halka-a, halka-b, halka-c
```

Bu sıra ilk bakışta şaşırtıcı görünebilir, çünkü bu derste önce ölçülen kural bağlamaların
son bağlanandan başlayarak bittiğiydi. Ama burada tek bir dış bağlama var — `zincir` —, üç
ayrı bağlama yok. `zincir` bittiğinde önce kendi `Iz` alanı biter (`halka-a`), ardından
kendi `Box<Zincir>` alanı biter; o `Box` da kendi içindeki değeri bitirirken önce onun
`Iz` alanını bitiriyor (`halka-b`), sonra kendi `Box`unu ve bu böyle sürüyor. Bitiş,
dıştan içe doğru ilerleyen tek bir zincirleme çağrı olduğu için kurulma sırasıyla aynı
yönde ilerliyor; bu, "Kap da Bir Sınıf" bölümündeki liste örneğinden farklı bir bitiş
biçimidir — orada çok sayıda bağımsız bağlama vardı, burada iç içe geçmiş tek bir bağlama
zinciri var.

Dört ölçüm bir araya geldiğinde tek bir resim çıkıyor: `Box`, bir değerin **nerede**
durduğunu değiştiren ama **kaç sahibi olduğunu** hiç değiştirmeyen bir kaptır. Değere
erişim biçimi aynı kalıyor, taşıma bitiş noktasını taşıyor ama sayıyı çoğaltmıyor, açık
bir çağrı erken bitirebiliyor ve bu tekil sahiplik sayesinde bir tip kendi türünden bir
sonraki halkayı taşıyabiliyor. Sıradaki sorunun zemini de tam burada kuruluyor: bu dört
ölçümün hiçbirinde sahiplik sayısı birden fazla olmadı — hep tek bir bağlama, tek bir
anda, o değerin sahibiydi.

## Özet

- Bir değer öbekte durduğunda da tek bir sahibi olur; `Box` bu sayıyı değiştirmez.
- Bir kabın içindeki tekil değer ile listedeki değerler farklı bitiş sırası kurallarına
  uyar: biri bildirimin tersini, öbürü ekleme sırasını izler.
- Öbekte durmak bir değerin okunma ve kullanılma biçimini değiştirmez.
- Öbekteki bir değer taşınsa bile defterde yalnızca tek bir bitiş kaydı oluşur.
- Aynı tip, kaynakta yapılana göre "kabıyla birlikte" ya da "açık çağrıda" sınıflarından
  birine düşebilir.
- Öbekte tekil sahiplik, kendine referans veren bir tipin derlenebilmesini sağlar; bir
  zincir tipinin bitiş sırası bu durumda kurulma sırasıyla aynı yönde ilerleyebilir.

## Sonraki Adım

Bu derste öbekteki bir değer taşınsa da, erken bırakılsa da, zincirlense de, sahibi hep
tek kaldı. Sıradaki ders bu varsayımı kaldırıyor: aynı değeri aynı anda birden çok
bağlamanın sahiplenebildiği bir düzenek — ve bu paylaşımın kaynaktan okunabilir bir
sayaçla nasıl izlendiği ölçülüyor.
