---
title: 'Referans Sayımı'
source: 'https://academia.sh/tr/kurslar/sahiplik/referans-sayimi'
course: 'Sahiplik ve Bellek Modeli'
language: tr
updated: '2026-09-13T05:09:25+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir paylaşılan değerin sayacının her kopyada arttığını, her bitişte azaldığını koşturarak gösterir'
    - 'Sayacın sıfıra inmesiyle değerin deftere düşmesinin aynı ana denk geldiğini doğrular'
    - 'Bir referans almanın sayacı değiştirmediğini, yalnızca kopyalamanın değiştirdiğini örnekle ayırt eder'
---

# Referans Sayımı

Bir Rc değerinin sayacının her kopyada arttığı, her bitişte azaldığı ve değerin ancak sayaç sıfıra inince deftere düştüğü ölçülüyor; bir referans almanın bu sayacı hiç değiştirmediği ve hangi kopyanın bırakıldığının değil kaç kopyanın kaldığının belirleyici olduğu gösteriliyor.

Önceki ders, öbekteki bir değerin taşınsa da, erken bırakılsa da, zincirlense de hep tek bir
sahibi olduğunu ölçtü. Bu dersin sorusu tam o varsayımı kaldırıyor: bir değerin sahibi birden
çok olabilir mi? Yanıt evet — ama bu evet bir kaçamak değil, kaynaktan okunabilen bir sayaçla
izlenen, belirlenimci bir paylaşımdır. Sayacın izlediği şey bir değerin bitiş noktasıdır;
Eşzamanlılık kursunun (M09/K03) ölçtüğü koşan bir birimin durması bu kursun sorusu değil.

`Rc<T>`, bir değeri öbeğe koyup kaç bağlamanın o değere ortak eriştiğini sayan bir kaptır.
Değer, bu sayaç sıfıra düşünceye kadar yaşar; sayaç sıfıra indiği an, önceki derste görülen
tekil sahiplik biter ve değer defterine düşer. Bu ders o sayacı doğrudan okuyarak, her
kopyalamada ve her bitişte ne olduğunu, hangi bağlamanın "sahip" sayıldığını ve hangisinin
sayılmadığını ölçüyor.

## Neden Bir Referans Yetmez

Ödünç Alma dersi, bir referansın ödünç aldığı değerden daha uzun yaşayamayacağını
ölçmüştü; Yaşam Süresi Kavramı dersi bu sınırı bir geçerlilik aralığı olarak adlandırdı.
Bu sınır, aynı değere birden çok yerden erişmek isteyen ama kaynaktaki tek sahiplik
bağlamasının ömrüyle sınırlı kalmak istemeyen bir kullanım için yetersiz kalır: referans,
sahibinin kapsamı kapanınca geçersiz olur, kaç yerden okunursa okunsun — sahibinin kendisi
hâlâ tektir. `Rc`, bu sınırı bir kopyanın kendisini de bir sahip yaparak aşıyor: artık
ödünç alan bir taraf değil, kendi başına bir sahip olan bir kopya söz konusu ve bu kopya
orijinal bağlamadan bağımsız olarak kendi kapsamının sonuna kadar yaşayabiliyor.

## Sahiplik Sayılabilir Hâle Geliyor

Bir değer `Rc::new` ile öbeğe konduğunda sayaç bire kurulur. `Rc::clone` çağrıldığında yeni
bir kopya üretilir, sayaç bir artar; kopyalardan biri bittiğinde sayaç bir azalır. Bu
kopyalar birbirinin **aynı** değerine erişir — her biri kendi ayrı bir değer taşımaz,
hepsi tek bir `Iz`yi paylaşır.

**PS5.** — "sayacın her kopyada arttığı ve her bitişte azaldığı" iddiası, aşağıdaki koşumun
`1, 2, 3, 2` sırasıyla basılan sayaç değerleriyle doğrulanıyor.

```rust
// referans_sayaci.rs — Rc'nin sayaci her kopyada artiyor, her bitiste azaliyor
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 paylasilan: Rc<Iz> = Rc::new(Iz::yeni("paylasilan", &defter));
        println!("kurulunca sayac: {}", Rc::strong_count(&paylasilan));

        let ikinci = Rc::clone(&paylasilan);
        println!("bir kopyadan sonra sayac: {}", Rc::strong_count(&paylasilan));

        {
            let _ucuncu = Rc::clone(&paylasilan);
            println!("iki kopyadan sonra sayac: {}", Rc::strong_count(&paylasilan));
            println!("ic kapsam biterken defter uzunlugu: {}", defter.borrow().len());
        }
        println!("ic kapsam bittikten sonra sayac: {}", Rc::strong_count(&paylasilan));
        println!("ikinci kopya hala okunabilir: {}", ikinci.ad);
    }
    let kayit = defter.borrow();
    println!("defterdeki kayit sayisi: {}", kayit.len());
    println!("kayitlar: {}", kayit.join(", "));
}
```

```
kurulunca sayac: 1
bir kopyadan sonra sayac: 2
iki kopyadan sonra sayac: 3
ic kapsam biterken defter uzunlugu: 0
ic kapsam bittikten sonra sayac: 2
ikinci kopya hala okunabilir: paylasilan
defterdeki kayit sayisi: 1
kayitlar: paylasilan
```

İç kapsam kapanırken `_ucuncu` bitiyor, ama defter uzunluğu sıfır kalıyor: `_ucuncu`nun
bitişi yalnızca sayacı ikiye indiriyor, `Iz` değerinin kendisini bitirmiyor. `paylasilan`
ve `ikinci` hâlâ aynı değere erişebiliyor — `ikinci.ad` okunduğunda hâlâ `paylasilan`
metnini veriyor, çünkü ikisi aynı değeri paylaşıyor. Dış kapsam kapandığında geri kalan iki
kopya da bitiyor, sayaç sıfıra iniyor ve ancak o an defterde tek bir kayıt beliriyor.
Üç kopyaya rağmen defterde tek kayıt olması, paylaşımın değeri **çoğaltmadığını**, yalnızca
ona erişen yol sayısını çoğalttığını gösteriyor.

## Kopyalamak Veri Kopyalamak Değildir

Yukarıdaki koşumda `Iz::yeni` yalnızca **bir kez** çağrılıyor — `paylasilan` kurulurken.
`ikinci` ve `_ucuncu`, `Rc::clone(&paylasilan)` ile üretiliyor; bu çağrı ne `Iz::yeni`yi
yeniden çalıştırıyor ne de `ad` alanını yeniden kuruyor. `ikinci.ad`in hâlâ `paylasilan`
metnini vermesi bir rastlantı değil: `ikinci` ayrı bir `Iz` değeri taşımıyor, `paylasilan`
ile **aynı** değere bakan ikinci bir erişim yolu taşıyor. Bu, bir dizginin ya da bir
listenin `.clone()` çağrısından farklıdır — onlarda içerik gerçekten kopyalanır ve
sonradan biri değiştirilse öbürü değişmez. `Rc::clone`, adındaki fiile rağmen, taşıdığı
değeri değil yalnızca sayacı ve erişimi çoğaltıyor. Bu fark, ilerleyen bir derste
paylaşılan verinin **değiştirilmesi** gündeme geldiğinde önemli sonuçlar doğuruyor: iki
kopyadan biri üzerinden yapılan bir değişiklik, öbür kopyadan da görülebilir hâle gelir,
çünkü aslında değişen tek bir değerdir.

## Her Değerin Kendi Sayacı Vardır

Bir programda birden çok paylaşılan değer varsa, her birinin sayacı ayrıdır. Bir değerin
kopyalanması ya da bitmesi, başka bir değerin sayacına dokunmaz.

```rust
// bagimsiz_sayaclar.rs — farkli degerlerin sayaclari birbirinden bagimsizdir
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 birinci: Rc<Iz> = Rc::new(Iz::yeni("birinci-deger", &defter));
    let ikinci: Rc<Iz> = Rc::new(Iz::yeni("ikinci-deger", &defter));

    let birinci_kopya = Rc::clone(&birinci);
    println!("birinci sayac: {}", Rc::strong_count(&birinci));
    println!("ikinci sayac: {}", Rc::strong_count(&ikinci));

    drop(birinci_kopya);
    drop(birinci);
    println!("defter (yalniz birinci bitti): {}", defter.borrow().join(", "));

    drop(ikinci);
    println!("defter (ikisi de bitti): {}", defter.borrow().join(", "));
}
```

```
birinci sayac: 2
ikinci sayac: 1
defter (yalniz birinci bitti): birinci-deger
defter (ikisi de bitti): birinci-deger, ikinci-deger
```

`birinci` bir kez kopyalandığı için sayacı iki, `ikinci` hiç kopyalanmadığı için sayacı
bir. `birinci`nin iki kopyası da bittiğinde `ikinci`nin sayacı hâlâ bir olarak kalıyor —
`ikinci` bu değişiklikten habersiz. Aynı `defter` her iki değer için de ortak kullanılıyor
(bu bir kayıt aracı, sayılan değerin kendisi değil), ama her `Iz`nin kendi `Rc` sarmalayıcısı
kendi sayacını tutuyor. Bir programda kaç ayrı paylaşılan değer varsa, o kadar ayrı ve
birbirinden bağımsız sayaç vardır.

## Paylaşım Sahiplik Kuralını İhlal Etmiyor, Genelliyor

Önceki derste kurulan "tek sahip" kuralı burada bozulmuyor, genelleniyor: sahip artık tek
bir bağlama değil, sayaç sıfıra düşene kadar aktif kalan kopyaların **kümesidir**. Sayaç
sıfıra indiği an kesin olarak bellidir ve bu an, koşumda her zaman aynı sırayla üretilen
bir kayıttır — bir sonraki adımın ne yapacağına bağlı bir tahmin değil, kaynaktaki kopya
sayısının doğrudan sonucudur. Bu, tek iş parçacığında çalışan sıradan bir tam sayı gibi
davranır: `Rc::clone` çağrısı bir kopya üretip sayacı artırıyor, kopyanın bitişi sayacı
azaltıyor ve iki işlem de aynı yerden — aynı kapsamdan — yürüyor.

Sayaç, tek tek adlandırılmış bağlamalarla sınırlı değildir; bir döngüde üretilen kopyalar
da aynı kurala uyar. Aşağıdaki koşum beş kopyayı bir listeye topluyor, sonra listeyi tek
seferde boşaltıyor.

```rust
// toplu_kopyalama.rs — bir donguyle uretilen kopyalar temizlenince sayac baslangica doner
use std::rc::Rc;

fn main() {
    let paylasilan: Rc<i32> = Rc::new(7);
    let mut kopyalar: Vec<Rc<i32>> = Vec::new();
    for _ in 0..5 {
        kopyalar.push(Rc::clone(&paylasilan));
    }
    println!("bes kopyadan sonra sayac: {}", Rc::strong_count(&paylasilan));

    kopyalar.clear();
    println!("kopyalar temizlenince sayac: {}", Rc::strong_count(&paylasilan));
}
```

```
bes kopyadan sonra sayac: 6
kopyalar temizlenince sayac: 1
```

Beş kopya listeye eklenince sayaç altıya çıkıyor — ilk kurulan `paylasilan` da bir kopya
sayılıyor. Liste tek seferde boşaltıldığında beş kopya art arda bitiyor ve sayaç bire
dönüyor; `paylasilan` kendisi hâlâ elde olduğu için değer henüz bitmiyor. Bu örnek `Iz`
düzeneğini kullanmıyor, çünkü burada ölçülen şey bir bitiş kaydı değil, sayacın kendisinin
toplu işlemler altında da aynı kuralı izlediği.

## Sayılan Şey Sahiptir, Ödünç Değil

Sayaç, yalnızca `Rc::clone` çağrılarını sayar. Paylaşılan değere bir **referans** almak —
onu okumak için ödünç almak — sayacı hiç değiştirmez, çünkü ödünç alan taraf değerin
sahibi değildir, yalnızca ona geçici olarak erişir.

**PS6.** — "bir referans almanın sayacı değiştirmediği" iddiası, aşağıdaki koşumda
`kurulunca sayac` ile `odunc alip okuduktan sonra sayac` satırlarının aynı değeri
(`1`) vermesiyle doğrulanıyor.

```rust
// odunc_sayaca_girmez.rs — bir referans almak Rc sayacini 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 oku(deger: &Iz) -> usize {
    deger.ad.len()
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    let paylasilan: Rc<Iz> = Rc::new(Iz::yeni("olcum-degeri", &defter));
    println!("kurulunca sayac: {}", Rc::strong_count(&paylasilan));

    let uzunluk = oku(&paylasilan);
    println!(
        "odunc alip okuduktan sonra sayac: {} (uzunluk {})",
        Rc::strong_count(&paylasilan),
        uzunluk
    );

    let kopya = Rc::clone(&paylasilan);
    println!("kopyaladiktan sonra sayac: {}", Rc::strong_count(&paylasilan));

    drop(kopya);
    println!("kopyayi birakinca sayac: {}", Rc::strong_count(&paylasilan));
}
```

```
kurulunca sayac: 1
odunc alip okuduktan sonra sayac: 1 (uzunluk 12)
kopyaladiktan sonra sayac: 2
kopyayi birakinca sayac: 1
```

`oku` işlevi `&Iz` alıyor, `Rc<Iz>`nin kendisini değil — bu yüzden çağrı sayacı hiç
etkilemiyor. Sayaç yalnızca `Rc::clone` çağrısıyla ikiye çıkıyor ve kopya açıkça
bırakıldığında yeniden bire dönüyor. Ödünç Alma dersinde kurulan "ödünç alınan değer
bitmiyor" ilkesi burada da geçerli: bir referans, değerin sahiplik defterine hiç
girmiyor; yalnızca kopyalar sahip sayılıyor, ödünç alanlar sayılmıyor.

Bu ayrım küçük görünse de yanlış anlaşılmaya açıktır, çünkü `Rc<Iz>` üzerinden bir
işleve `&paylasilan` geçirmek ile `Rc::clone(&paylasilan)` geçirmek yüzeysel olarak
benzer görünür — ikisi de bir `&` işareti taşıyabilir. Aradaki fark şudur: `oku(&paylasilan)`
çağrısı `Rc<Iz>`yi ödünç alıp içindeki `&Iz`ye otomatik olarak iniyor, hiçbir yeni sahip
kurmuyor; `Rc::clone(&paylasilan)` ise açıkça yeni bir sahip kopyası üretiyor. Kod
okunurken bu iki niyeti ayırt etmenin yolu, çağrının `clone` adını taşıyıp taşımadığına
bakmaktır — sayaç yalnızca o adı taşıyan çağrıya tepki verir.

## Sıra Değil, Sayı Belirleyici

Önceki derste bir kabın içindekilerin bitiş **sırası** ölçülmüştü — hangi değerin önce,
hangisinin sonra bittiği belirleyiciydi. Referans sayımında durum farklıdır: hangi
kopyanın hangi sırayla bırakıldığı değeri bitirmez, yalnızca **kaç** kopyanın kaldığı
belirler.

**PS7.** — "değerin, hangi kopyanın değil son kalan kopyanın bırakılmasıyla bittiği"
iddiası, aşağıdaki koşumda dört kopyadan ilk kurulanın ortadan bırakılmasına rağmen
defterin boş kalmasıyla, yalnızca son kopya giderken dolmasıyla doğrulanıyor.

```rust
// sira_onemsiz.rs — Rc'de hangi kopyanin birakildigi degil, kac kopya kaldigi belirleyici
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 paylasilan: Rc<Iz> = Rc::new(Iz::yeni("son-kopya-birakilinca-biten", &defter));
    let a = Rc::clone(&paylasilan);
    let b = Rc::clone(&paylasilan);
    let c = Rc::clone(&paylasilan);
    println!("dort kopyadan sonra sayac: {}", Rc::strong_count(&a));

    drop(b);
    println!("ortadaki kopya birakilinca sayac: {}", Rc::strong_count(&a));
    println!("defter hala bos mu: {}", defter.borrow().is_empty());

    drop(paylasilan);
    println!("ilk kurulan kopya birakilinca sayac: {}", Rc::strong_count(&a));
    println!("defter hala bos mu: {}", defter.borrow().is_empty());

    drop(a);
    drop(c);
    let kayit = defter.borrow();
    println!("son kopya da birakilinca kayit: {}", kayit.join(", "));
}
```

```
dort kopyadan sonra sayac: 4
ortadaki kopya birakilinca sayac: 3
defter hala bos mu: true
ilk kurulan kopya birakilinca sayac: 2
defter hala bos mu: true
son kopya da birakilinca kayit: son-kopya-birakilinca-biten
```

Dört kopyadan `b` bırakılıyor, sonra ilk kurulan `paylasilan` bırakılıyor — kuruluş
sırasına göre ne ilk ne son olan bir kopya, sonra da en eski kopyanın kendisi gidiyor. İki
bırakmadan sonra bile defter boş kalıyor, çünkü geriye hâlâ iki kopya (`a` ve `c`) var.
Değer ancak bu ikisi de bırakıldığında biter. Bir önceki derste bir kabın içindekilerin
bitişi **hangi sırayla** eklendiğine bağlıydı; burada bitiş yalnızca **kaç** kopyanın
kaldığına bağlı — hangi kopyanın adı, hangi sırayla bırakıldığı sonucu değiştirmiyor. Bu
fark, iki kap türü arasındaki temel ayrımı özetliyor: bir liste ya da bir `Box`, tek bir
sahiplik zincirinin **konumunu** kaydeder ve bu yüzden sıraya duyarlıdır; bir `Rc`,
sahiplik zincirinin **uzunluğunu** kaydeder ve bu yüzden yalnızca sayıya duyarlıdır.

Yukarıdaki koşumlarda kullanılan açık `drop` çağrısı, Öbekte Tekil Sahiplik dersinde
görülen açık çağrı fikrini burada da sürdürüyor, ama sonucu farklıdır. Orada bir `Box`
üzerinde açık çağrı değerin kendisini erkenden bitiriyordu — tek sahip olduğu için başka
seçenek yoktu. Burada aynı çağrı yalnızca **bir kopyayı** bırakıyor; değerin kendisi,
geriye başka kopya kaldığı sürece bitmiyor. Aynı `drop` işlevi, tek sahiplikte kesin bir
bitiş, paylaşımlı sahiplikte ise koşullu bir azaltma anlamına geliyor — anlam, çağrıldığı
değerin sahiplik biçimine göre değişiyor.

Dört koşum bir araya geldiğinde, referans sayımının sahiplik kuralını nasıl genellediği
netleşiyor. Sayaç her zaman tek bir yerden, tek bir sırayla güncelleniyor; kopyalamak
veriyi değil erişimi çoğaltıyor; bir referans hiçbir zaman bu sayıma girmiyor; ve
bitişi belirleyen şey kopyaların kimliği değil miktarıdır. Bu dört özellik birlikte, hâlâ
belirlenimci ve kaynaktan okunabilir bir bitiş noktası sağlıyor — sayaç sıfıra indiği an,
tıpkı önceki derste tek sahipli bir değerin kapsam sonu gibi, koşumda kesin ve tekrarlanır
biçimde görülüyor.

## Özet

- `Rc<T>`, bir değeri öbeğe koyup ona erişen kopya sayısını sayan bir kaptır.
- Sayaç her `Rc::clone` çağrısında artar, her kopyanın bitişinde azalır.
- Değer, ancak sayaç sıfıra indiğinde defterine düşer — ömrü **kabıyla birlikte**, son
  kalan kopyanın bitişinde biter; bu an kaynaktan okunabilir ve
  koşumda her zaman aynı sırayla üretilir.
- Bir referans almak sayacı değiştirmez; yalnızca kopyalamak değiştirir.
- Değerin bitişi hangi kopyanın bırakıldığına değil, kaç kopyanın kaldığına bağlıdır.
- `Rc::clone` taşınan değeri değil, sayacı ve erişimi çoğaltır; kopyalar aynı değere bakar.

## Sonraki Adım

Bu derste ölçülen sayaç, tek bir bağlamda, sıradan bir tam sayı gibi güncellendi: her
kopyalama ve her bitiş aynı kapsamdan, aynı sırayla yürüdü. Sıradaki ders aynı sayma
işini yapan ama sayacın kendisini farklı bir biçimde güncelleyen bir türü ölçüyor — davranış
aynı kalıyor, yalnızca sayacın güncellenme biçimi değişiyor; hangi bağlamda bu farkın
gerektiği, bu dersin kapsamının dışında kalıyor.
