---
title: RAII
source: 'https://academia.sh/tr/kurslar/cpp-temelleri/raii'
course: 'C++ Temelleri ve Nesne Tasarımı'
language: tr
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - "RAII'nin bir kaynağı yapıcıda alıp yıkıcıda bıraktığını tanımlar"
    - 'Bir koruyucunun dokunduğu nesnenin kendisi değil içindeki üye olduğunu ölçer'
    - 'Erken çıkış yollarında bile yıkıcının koştuğunu gösterir'
---

# RAII

Bir koruyucunun aldığı ve bıraktığı üyenin, koruyucu nesnenin kendisi değil içindeki bir parça olduğunu ölçer.

Önceki ders bir nesnenin ne zaman kurulduğunu ve yok olduğunu, adı olsun ya da olmasın,
ölçtü. Bu ders o bilgiyi bir amaç için kullanır: bir kaynağı — burada basit bir sayaç
kaynağı, gerçek programlarda bellek, dosya tanıtıcısı ya da kilit olabilir — güvenle serbest
bırakmak. Ölçüm sınıfı bu kez **parça**: bir koruyucunun aldığı ve bıraktığı şey, koruyucunun
kendisi değil, içindeki bir veri üyesidir.

## RAII Tanımı

**RAII** (Resource Acquisition Is Initialization — kaynak edinimi ilk değerlemedir), bir
kaynağın bir nesnenin yapıcısında alınıp yıkıcısında bırakılmasını öngören bir tasarım
kalıbıdır. Kaynağı tutan nesne yaşadığı sürece kaynak da geçerlidir; nesne — adlandırılmış
ya da geçici, önceki derste görüldüğü gibi — herhangi bir yoldan yaşam süresinin sonuna
geldiğinde yıkıcı çalışır ve kaynağı bırakır. Bu, kaynağı elle bırakmayı (`serbest_birak()`
gibi bir işlevi her çağıran kodda tek tek çağırmayı) gereksiz kılar: kaynağı tutan nesne
hangi yoldan yok olursa olsun (işlevin sonuna gelme, erken `return`, istisna fırlatma),
yıkıcı **her zaman** çalışır.

RAII'nin karşıtı, kaynağı bir yapıcı/yıkıcı çiftine değil, çağıranın disiplinine bırakmaktır:
bir `kaynak_ac()` işlevi çağrılır, kullanılır, ve kodun her çıkış noktasında elle bir
`kaynak_kapat()` çağrılması beklenir. Bu yaklaşımın kırılganlığı, kod büyüdükçe ortaya çıkar
— bir işleve yeni bir erken `return` eklendiğinde, o `return`'den önce `kaynak_kapat()`
çağrısının da eklenmesi gerekir; eklenmezse kaynak sızar (leak — kaynağın hiç bırakılmadan
programın geri kalanında geçerli kalmaya devam etmesi). RAII bu riski, bırakma kararını
kaynağı tutan kodun değil, kaynağı **tutan nesnenin türünün** sorumluluğuna vererek ortadan
kaldırır: `Koruyucu`'yu kullanan kod hiçbir zaman bir bırakma çağrısı yazmaz, çünkü bu
çağrı zaten `Kaynak::~Kaynak()` içinde, bir kez, sınıfın kendisinde yazılıdır. Bu dersin ilk
bölümünde iki sınıf tanımlanır: kaynağı gerçekten tutan `Kaynak`, ve onu bir üye olarak saran
`Koruyucu`.

```cpp
// kaynak.hpp — sayilarla temsil edilen basit bir kaynak
#ifndef KAYNAK_HPP
#define KAYNAK_HPP

#include <cstdio>

class Kaynak {
public:
    explicit Kaynak(int kimlik) : kimlik_(kimlik) {
        std::printf("kaynak alindi kimlik=%d\n", kimlik_);
    }

    ~Kaynak() {
        std::printf("kaynak birakildi kimlik=%d\n", kimlik_);
    }

    int kimlik() const { return kimlik_; }

private:
    int kimlik_;
};

#endif
```

```cpp
// koruyucu.hpp — kaynagi tutan uyeyi alan ve birakan koruyucu
#ifndef KORUYUCU_HPP
#define KORUYUCU_HPP

#include "kaynak.hpp"

class Koruyucu {
public:
    explicit Koruyucu(int kimlik) : kaynak_(kimlik) {}

    int kimlik() const { return kaynak_.kimlik(); }

private:
    Kaynak kaynak_;
};

#endif
```

## Koruyucunun Bıraktığı, Kendisi Değil İçindeki Üyedir

`Koruyucu`'nun kendi bir yapıcısı ve derleyicinin ürettiği bir yıkıcısı vardır; `Koruyucu`
`kaynak_` üyesini kendi kurduğunda `Kaynak` yapıcısı çalışır, kendi yok olduğunda `kaynak_`
yıkılır ve `Kaynak` yıkıcısı çalışır. Buradaki soru: koruyucunun aldığı ve bıraktığı şey,
`Koruyucu` nesnesinin kendisi mi, yoksa içindeki `kaynak_` üyesi mi?

```cpp
// parca-olcumu.cpp — koruyucunun tuttugu kaynak koruyucunun kendisi mi ici mi
#include <cstdio>

#include "koruyucu.hpp"

int main() {
    std::printf("blok basladi\n");
    {
        Koruyucu k(7);
        std::printf("kimlik %d\n", k.kimlik());
    }
    std::printf("blok bitti\n");
    return 0;
}
```

```text
blok basladi
kaynak alindi kimlik=7
kimlik 7
kaynak birakildi kimlik=7
blok bitti
```

**SK8.** `Kaynak`'ın yapıcısı `Koruyucu k(7)` satırında, `Koruyucu`'nun kendi yapıcı gövdesi
çalışmadan önce, üye ilk değer listesindeki `kaynak_(kimlik)` ile tetiklenir — `kaynak
alindi` satırı bu yüzden `blok basladi`'dan hemen sonra, `Koruyucu`'nun kendi gövdesi hiçbir
şey basmadan önce görülür. Kaynağı gerçekte alan `Kaynak` nesnesidir, ve bu nesne
`Koruyucu`'nun **kendisi değil**, onun bir üyesidir — `kaynak_`, `Koruyucu`'nun bellek
aralığının içinde bir alt nesnedir (subobject), ayrı, bağımsız bir nesne değildir. Bunun
kanıtı sıralamadadır: `k` blok sonunda yok olurken önce `Koruyucu`'nun (derleyicinin
ürettiği, hiçbir şey basmayan) yıkıcısı çalışır, ardından `Koruyucu`'nun üyesi olduğu için
`kaynak_`'ın yıkıcısı çalışır — `kaynak birakildi` satırı bu yüzden `blok bitti`'den önce
görülür. Eğer `kaynak_` `Koruyucu`'dan bağımsız, ayrı bir nesne olsaydı, onun yıkımı
`Koruyucu`'nun yıkımına bağlı olmazdı; oysa burada ikisi aynı anda, aynı kapsamın
kapanmasıyla tetiklenir — çünkü biri diğerinin parçasıdır.

Burada dikkat edilmesi gereken bir isim çakışması yoktur: `Kaynak` ile `Koruyucu`'nun ikisi
de kendi başlarına birer sınıftır, biri diğerini üye olarak barındırır. `Koruyucu`'nun
kendi yapıcısı `explicit Koruyucu(int kimlik) : kaynak_(kimlik) {}` gövdesizdir — tüm işi
üye ilk değer listesi yapar, `kaynak_`'ı `kimlik` ile kurar. `Koruyucu`'nun kendi bir
yıkıcısı yazılmamıştır; derleyici bir tane üretir, ve bu üretilen yıkıcı hiçbir şey
basmadan yalnız `kaynak_`'ın yıkıcısını tetikler — bu, önceki dersteki `Ciftlik` örneğinde
görülen aynı davranıştır: bir sınıf kendi yıkıcısını yazmasa bile, üyelerinin yıkıcıları
yine de çalışır.

## Erken Çıkış Yollarında Yıkıcı Yine Çalışır

RAII'nin asıl değeri, kaynağı bırakan kodu tek bir yere (yıkıcıya) yazıp, o kodun **her**
çıkış yolunda çalışmasını derleyiciye bırakmaktır — işlevin normal sonu, erken `return`,
ya da bir istisna fırlatıldığında bile.

```cpp
// erken-cikis.cpp — koruyucu erken return yolunda da birakiyor mu
#include <cstdio>

#include "koruyucu.hpp"

static void calistir(bool erkenCik) {
    Koruyucu k(9);
    std::printf("calistir basladi kimlik=%d\n", k.kimlik());
    if (erkenCik) {
        std::printf("erken cikiliyor\n");
        return;
    }
    std::printf("normal bitiyor\n");
}

int main() {
    calistir(true);
    std::printf("main devam ediyor\n");
    return 0;
}
```

```text
kaynak alindi kimlik=9
calistir basladi kimlik=9
erken cikiliyor
kaynak birakildi kimlik=9
main devam ediyor
```

**SK9.** `calistir(true)` `if` bloğu içindeki `return`'e ulaştığında, `k`'nin kapsamı
(işlev gövdesi) sona erer ve derleyici `k`'nin yıkıcısını **`return`'den hemen önce**
çalıştırır — `kaynak birakildi` satırı `erken cikiliyor`'dan sonra, ama `main devam
ediyor`'dan önce görülür. Bu davranış `if` dalına bakılmaksızın aynıdır: `calistir(false)`
çağrılsaydı `normal bitiyor` satırından sonra yine aynı yıkıcı çalışırdı. Kaynağı bırakan kod
yalnız `Kaynak::~Kaynak()` içinde bir kez yazılıdır; `calistir`'in kendisi hiçbir bırakma
çağrısı yapmaz.

Bu güvence yalnız `if`/`return` gibi düzenli kontrol akışı için değil, C++'ın istisna
mekanizması için de geçerlidir: bir işlev gövdesinde bir istisna fırlatılırsa (`throw`),
yığıt o istisna bir `catch` bloğu tarafından yakalanana kadar **çözülür**
(yığıt çözülmesi) — bu çözülme sırasında, çözülen her kapsamdaki yerel nesnelerin
yıkıcıları, tıpkı normal bir `return`'de olduğu gibi sırayla çalıştırılır. `calistir`
içinde `k`'den sonra bir `throw` satırı olsaydı, `k`'nin yıkıcısı yine de istisna
`calistir`'in dışına çıkmadan önce çalışırdı. Bu kurs istisna fırlatma ve yakalamayı
öğretmez — o başka bir konudur — ama RAII'nin gerçek gücü tam olarak buradan gelir: kaynak
bırakma kodu, kontrol akışının **hangi yoldan** çıktığını bilmek zorunda değildir, çünkü
yıkıcı her yoldan çalışır.

## Kaynağı Referansla Tutmanın Riski

RAII'nin sağlamlığı, koruyucunun kaynağı **değerle** (bir üye olarak, kendi ömrüyle bağlı)
tutmasına dayanır. Bir koruyucu kaynağı referansla ya da işaretçiyle tutarsa, koruyucunun
kendi ömrü ile kaynağın gerçek sahibinin ömrü ayrışabilir — koruyucu hâlâ yaşarken kaynak
zaten yok olmuş olabilir. `Koruyucu` bu riski taşımaz çünkü `kaynak_` bir referans ya da
işaretçi değil, doğrudan bir `Kaynak` değeridir; `Koruyucu` yaşadığı sürece `kaynak_` de
yaşar, çünkü aynı nesnenin bir parçasıdır. Bir koruyucu kaynağı değerle değil de bir
işaretçiyle tutacak şekilde yanlış tasarlansaydı — `Kaynak* kaynak_;` gibi — koruyucunun
kopyalanması yalnız işaretçiyi kopyalardı, gerçek `Kaynak` nesnesini değil; iki koruyucu aynı
kaynağı işaret eder, biri yıkıcısında kaynağı bırakınca diğeri artık geçersiz bir kaynağa
işaret eder hâle gelirdi. Bu ders bu hatayı koşturmaz — yalnız düzyazıda anılır — çünkü
kaynağın iki kez bırakılması tanımsız davranıştır.

Bu paylaşım sorununu standart kütüphanenin hazır RAII sarmalayıcılarıyla çözmek K05'in
konusudur; bu kurs kaynağı kendi yazdığı sınıflarla yönetir. M10/K02'nin (Rust) sahiplik
sistemi ve M11/K02'nin kaynak yönetimi aynı fikrin — bir kaynağın tam olarak bir sahibi
olması ve sahibin ömrü bittiğinde kaynağın otomatik bırakılması — farklı dillerdeki
karşılıklarıdır; bu ders o karşılaştırmayı derinleştirmez.

`Koruyucu`'nun kendi tasarımı bu riskten nasıl kaçındığını daha ayrıntılı görmek
faydalıdır. `kaynak_` bir `Kaynak` **değeridir**, bir `Kaynak*` ya da `Kaynak&` değildir;
bu yüzden `Koruyucu` nesnesinin bellek düzeninde `kaynak_`'ın kendisi (yalnız ona işaret
eden bir adres değil) yer alır. Bir `Koruyucu` kopyalandığında — bu kursun bir sonraki
dersinin konusu — `kaynak_` de kopyalanır, çünkü o da `Koruyucu`'nun bir parçasıdır; iki
`Koruyucu` iki ayrı `Kaynak` taşır, aynı kaynağı paylaşmazlar. Bir işaretçiyle tutulan bir
kaynakta bu doğru olmaz: işaretçinin kopyalanması yalnız adresi kopyalar, gösterilen nesneyi
değil, bu yüzden iki koruyucu aynı kaynağa işaret etmeye başlar. Değerle tutmanın bu
sonucu — kopyalamanın kaynağı da beraberinde kopyalaması — RAII'nin güvenilirliğinin bir
parçasıdır ve bir sonraki derste ayrıntılı ölçülür.

Bir kaynağı değerle tutmanın bir sınırı da vardır: kaynak, tutan nesnenin bellek düzeninde
yer aldığı için, kaynağın boyutu (ya da en azından kaynağı temsil eden tanıtıcının boyutu)
derleme zamanında bilinmelidir. `Kaynak` burada yalnız bir `int` taşıdığı için bu sorun
görünmez; gerçek bir kaynak — açık bir dosya, bir ağ bağlantısı — genellikle işletim
sisteminin verdiği sabit boyutlu bir tanıtıcı (handle, örneğin bir tamsayı ya da bir
işaretçi) ile temsil edilir, bu yüzden aynı değerle-tutma stratejisi gerçek kaynaklar için
de çalışır.

## Çoklu Kaynak Tutan Bir Koruyucu

Bir koruyucunun tek bir kaynak yerine birden çok kaynak tutması da aynı kuralı izler: her
kaynak, koruyucunun bir başka üyesi olur, ve her üyenin kurulma/yıkılma sırası önceki
derste ölçülen bildirim sırası kuralına uyar. İki `Kaynak` üyesi olan bir `CiftKoruyucu`
tasarlansaydı, üyeler bildirim sırasıyla kurulur, ters sırada yıkılırdı — tıpkı `Ciftlik`
örneğindeki `birinci_`/`ikinci_` gibi. Bu ders `CiftKoruyucu`'yu koşturmaz, çünkü tek bir
kaynağın alınıp bırakılması RAII'nin çekirdek fikrini göstermek için yeterlidir; ama bu
genellemenin doğrudan önceki dersten geldiğini görmek önemlidir — RAII yeni bir dil kuralı
eklemez, yalnız yapıcı/yıkıcı sırasını bir amaç için kullanır.

## Sınırlayıcı Ölçüm

Bu dersin ölçtüğü ifade **parça** sınıfındadır: `kaynak_`, `Koruyucu`'nun kendisi değil,
onun içindeki bir alt nesnedir, ve `Koruyucu`'nun yaşam süresiyle aynı yaşam süresine
sahiptir. Ama RAII'nin güvencesi koruyucunun **kaynağı değerle tutmasına** bağlıdır — bir
koruyucu kaynağa yalnız bir referans tutuyorsa (kaynağın gerçek sahibi başka bir nesneyse),
koruyucu korunan nesneden **uzun yaşamamalıdır**; koruyucu hâlâ yaşarken korunan nesne yok
olursa, koruyucunun referansı sarkan hâle gelir ve koruyucunun yıkıcısı (varsa) geçersiz bir
nesneye erişmeye çalışabilir. Bu ders bu riski koşturmaz, çünkü koşturmak tanımsız davranışı
tetikler; `Koruyucu` burada kaynağı her zaman değerle tuttuğu için bu risk zaten yoktur.

Bu sınırın pratik bir sonucu, bir koruyucu tasarlarken "bu kaynağın gerçek sahibi kim?"
sorusunun her zaman açıkça yanıtlanması gerektiğidir. `Koruyucu`'da yanıt nettir: `Koruyucu`
kendisi sahiptir, çünkü `kaynak_` onun bir değer üyesidir. Bir koruyucu bunun yerine
"başka bir yerde yaşayan bir kaynağı yalnız gözlemliyorum" demek isteseydi — örneğin bir
işlevin parametresinde alınan bir `Kaynak&`'i saklamak isteseydi — bu artık RAII değil,
yalnız bir referans tutmak olurdu, ve kaynağı bırakma sorumluluğu koruyucuda olmazdı. İki
tasarım da C++'ta geçerlidir, ama birbirine karıştırılmamalıdır: bir sınıfın yıkıcısı
yalnız **kendi sahip olduğu** kaynakları bırakmalıdır, ödünç aldığı bir kaynağı değil.

Bu ders boyunca ölçülen üç örnek — kurulma sırasının kanıtı, erken çıkışta yıkıcının
çalışması, kaynağın değerle tutulması — birlikte RAII'nin neden bir "en iyi uygulama"dan
fazlası olduğunu gösterir: bu, dilin yapıcı/yıkıcı ve bildirim sırası kurallarının doğrudan
bir sonucudur, ayrı bir mekanizma değildir. Bir sonraki dersin kopyalama sorusu da aynı
temelin üstüne kurulur — bir `Koruyucu` kopyalandığında `kaynak_` de kopyalanacaktır, ama
bu kopyanın "derin" mi "sığ" mı olduğu, kaynağın türüne bağlı olarak farklı sonuçlar
doğurabilir.

## Özet

- Bu dersin ölçtüğü ifade **parça** sınıfındadır: `kaynak_`, `Koruyucu` nesnesinin
  kendisi değil, onun bir alt nesnesidir.
- RAII bir kaynağı yapıcıda alır, yıkıcıda bırakır; kaynağı elle bırakan kod gerekmez.
- Yıkıcı, kapsamın nasıl sona erdiğine bakılmaksızın çalışır — normal bitiş, erken
  `return`, ya da istisna fırlatma, hepsinde aynıdır.
- Kaynağı **değerle** tutan bir koruyucu, koruyucunun ömrüyle kaynağın ömrünü birleştirir;
  referansla tutan bir koruyucu bu güvenceyi kaybeder.
- Akıllı işaretçiler RAII'yi paylaşılan kaynaklara genişletir; bu kursun kapsamı dışındadır
  (K05).

## Sonraki Adım

Bu ders bir kaynağın yapıcı/yıkıcı çiftiyle nasıl güvenle tutulduğunu ölçtü; bir sonraki
ders bir nesne **kopyalandığında** bu güvencenin ne olduğunu sorar — kopyalayan yapıcının
kendi kaynağını mı aldığını, yoksa orijinaliyle paylaştığını mı ölçer.
