---
title: 'Yapıcılar ve Yıkıcılar'
source: 'https://academia.sh/tr/kurslar/cpp-temelleri/yapicilar-ve-yikicilar'
course: 'C++ Temelleri ve Nesne Tasarımı'
language: tr
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Örtük tip dönüşümüyle kurulan bir argümanın geçici nesne olduğunu ölçer'
    - 'explicit anahtar sözcüğünün örtük kurmayı nasıl engellediğini uygular'
    - 'Üye ilk değer listesi ve yapıcı zincirinin sırasını gösterir'
---

# Yapıcılar ve Yıkıcılar

Bir int'ten örtük kurulan argümanın adsız, geçici bir nesne olduğunu ve yaşam süresini yapıcı/yıkıcı çiftiyle ölçer.

Önceki ders bir üye işlevin hangi nesneyle çalıştığını `this` üzerinden ölçtü — ama o nesne
her zaman zaten vardı. Bu ders aynı soruyu bir nesnenin **var olma anına** sorar: bir
**yapıcı** (constructor — sınıfın adıyla aynı adı taşıyan, nesne kurulurken bir kez çalışan
üye işlev) ne zaman çağrılır, ve bir **yıkıcı** (destructor — `~` önekli, nesne yok olurken
bir kez çalışan üye işlev) ne zaman çalışır? Ölçüm sınıfı bu kez **geçici**: bir işlev
çağrısının bir argümanından örtük olarak kurulan, adı olmayan bir nesnenin ömrünü
izleyecek.

## Yapıcı ve Yıkıcı

Bir yapıcı, sınıfla aynı adı taşır, dönüş tipi yoktur (`void` bile yazılmaz) ve bir nesne
kurulurken derleyici tarafından çağrılır. Bir yıkıcı `~SinifAdi()` biçimindedir, bağımsız
değişken almaz, ve bir nesne yaşam süresinin sonuna geldiğinde derleyici tarafından çağrılır
— programcı onu elle çağırmaz. Bir sınıf hiç yapıcı yazmazsa derleyici **varsayılan yapıcı**
üretir (argüman almayan, veri üyelerini kendi varsayılan değerleriyle kuran); bir
yapıcı yazılırsa bu üretim durur.

Bir sınıfın birden çok yapıcısı olabilir — parametre sayısı ya da tipi farklı olduğu sürece
aynı işlev bindirimi (overload) kurallarıyla ayrılırlar. Buna karşılık bir sınıfın yalnız
**bir** yıkıcısı olabilir; yıkıcı argüman almadığı için bindirilemez.

Yapıcı ile sıradan bir üye işlev arasındaki en büyük fark, yapıcının çalıştığı anda nesnenin
**henüz tamamlanmamış** olmasıdır. `Tutar(int kurus)` çalışırken `kurus_` üye ilk değer
listesindeki `kurus_(kurus)` ile kurulur; gövde çalışmaya başladığında `kurus_` artık
geçerli bir değerdedir ve gövde içinde okunabilir, ama gövde çalışana kadar nesnenin diğer
üyeleri (bu sınıfta yalnız `kurus_` var, ama çok üyeli bir sınıfta sıradaki üyeler) henüz
kurulmamış olabilir. Bu yüzden bir yapıcının gövdesinde `this` üzerinden başka bir üye
işlevi çağırmak — özellikle sanal bir üye işlevi, bu kursun kapsamı dışında kalan bir konu
— nesnenin henüz tam kurulmamış bir durumuna erişme riski taşır; bu ders böyle bir çağrı
yapmaz.

Yıkıcının konumu simetriktir: yıkıcı çalıştığında nesne hâlâ tam ve geçerlidir, ama yıkıcı
döndükten sonra nesne artık yok sayılır — üye değişkenlerin belleği hâlâ durabilir ama
programın onlara erişmesi tanımsız davranıştır (bu kursun M11/K02'den devraldığı kural:
tanımsız davranış hiçbir zaman koşturulmaz, yalnız düzyazıda anılır). `Tutar::~Tutar()`
gövdesi `kurus_`'ü son kez okuyup basar; bu satırdan sonra hiçbir kod aynı nesnenin
`kurus_`'üne erişmemelidir.

```cpp
// tutar.hpp — bir yapici, bir yikici, bir de yapici zinciri
#ifndef TUTAR_HPP
#define TUTAR_HPP

#include <cstdio>

class Tutar {
public:
    Tutar(int kurus) : kurus_(kurus) {
        std::printf("yapici calisti kurus=%d\n", kurus_);
    }

    ~Tutar() {
        std::printf("yikici calisti kurus=%d\n", kurus_);
    }

    int kurus() const { return kurus_; }

private:
    int kurus_;
};

#endif
```

**SK5.** `Tutar(int kurus)` bir argüman alır ve gövdesinden önce çalışan `:
kurus_(kurus)` bir **üye ilk değer listesi**dir (member initializer list) — `kurus_` veri
üyesini gövde çalışmadan önce `kurus` değeriyle kurar. Gövde içinde `kurus_ = kurus` yazmak
da aynı sonucu verirdi, ama ilk değer listesi kurmayla atamayı ayırır: gövde çalıştığında
`kurus_` zaten vardır, yalnız değiştirilir.

## Örtük Kurma ve `explicit`

`Tutar(int kurus)` **tek** bir `int` argüman alan bir yapıcıdır; C++ böyle bir
yapıcıyı **örtük tip dönüşümü** için de kullanır. `goster(Tutar t)` diye bir işlev
`goster(5)` ile çağrılırsa, derleyici `5`'i `Tutar`'a dönüştürmek için bu yapıcıyı örtük
olarak çağırır — kurulan nesnenin adı yoktur, `main`'de hiçbir değişken görünmez, ama nesne
gerçekten vardır ve yapıcısı gerçekten çalışır.

```cpp
// gecici-olcumu.cpp — int'ten ortuk kurulan bir tutar gecici midir
#include <cstdio>

#include "tutar.hpp"

static void goster(Tutar t) {
    std::printf("goster icinde kurus=%d\n", t.kurus());
}

int main() {
    std::printf("cagridan once\n");
    goster(5);
    std::printf("cagridan sonra\n");
    return 0;
}
```

```text
cagridan once
yapici calisti kurus=5
goster icinde kurus=5
yikici calisti kurus=5
cagridan sonra
```

**SK6.** `goster(5)` çağrısında `5` önce `Tutar(5)` ile bir `Tutar` nesnesine dönüştürülür —
bu nesnenin adı yoktur, bu yüzden **geçici**dir. Bu geçici, `goster`'in parametresi `t`'ye
kopyalanır (ya da doğrudan onun yerine kurulur — bu kursun kapsamı dışında kalan bir
derleyici optimizasyonu); `goster` döndüğünde `t`'nin yıkıcısı çağrılır ve çıktı sırası
bunu gösterir: yapıcı çağrıdan hemen sonra, yıkıcı `goster` döndükten hemen sonra, ama
`cagridan sonra` satırından **önce** çalışır — geçicinin ömrü `goster(5);` ifadesiyle
sınırlıdır, `main`'in geri kalanına taşmaz.

Bu örtük dönüşüm her zaman istenmez: `goster(5)` yazıldığında `5`'in bir `Tutar` olarak mı
yoksa yanlışlıkla bir tamsayı olarak mı geçirildiği kod okuyucusuna açık değildir. `explicit`
anahtar sözcüğü bunu engeller: `explicit Tutar(int kurus)` yazılsaydı, `goster(5)` derlenmez,
yalnız `goster(Tutar(5))` ya da `goster(Tutar{5})` gibi açık bir kurma derlenirdi. Bu ders
`Tutar`'ı `explicit` yazmadan bırakır çünkü ölçülmek istenen tam olarak örtük kurmanın
ürettiği geçicidir; ama bir sınıf yazarı tek-bağımsız-değişkenli her yapıcıyı `explicit`
yapmayı düşünmelidir — bu kursun ilerideki derslerinde yazılan yapıcılar da aksi
belirtilmedikçe `explicit` olarak yazılır.

Örtük dönüşümün riski yalnız okunabilirlik değildir. İki argüman zinciri örtük
kurmaya izin verdiğinde — örneğin `Tutar` bir yapıcıdan başka bir sınıfa örtük dönüşüyorsa —
derleyici bir çağrıyı beklenmedik bir zincirle derleyebilir; C++ standardı bir çağrıda
**en fazla bir** örtük kullanıcı tanımlı dönüşüme izin vererek bunu sınırlar, ama tek
adımlık örtük dönüşüm bile kod okuyanın beklemediği bir yapıcı çağrısı gizleyebilir.
`goster(5)` örneğinde bu risk küçüktür çünkü `Tutar`'ın tek yapıcısı vardır ve niyet
açıktır; büyük bir sınıf hiyerarşisinde aynı örtük kurma, çağıranın fark etmediği bir
nesne kurma maliyetini (yapıcı çalışması, yıkıcı çalışması) sessizce ekleyebilir. `explicit`
bu sessizliği kaldırır: her kurma kaynak kodda görünür bir `Tür(...)` çağrısı olarak
görünmek zorunda kalır.

## Yapıcı Zinciri ve Ters Sıra Yıkım

Birden çok veri üyesi olan bir sınıfta üye ilk değer listesi, üyelerin **bildirim
sırasıyla** kurulmasını sağlar — listede yazılma sırası değil, sınıf gövdesindeki bildirim
sırası geçerlidir. Yıkım bunun tam tersi sırada olur: en son kurulan üye en önce yıkılır.

```cpp
// ciftlik.cpp — birden fazla uyenin kurulma ve yikilma sirasi
#include <cstdio>

#include "tutar.hpp"

class Ciftlik {
public:
    Ciftlik() : birinci_(1), ikinci_(2) {
        std::printf("ciftlik yapicisi calisti\n");
    }

private:
    Tutar birinci_;
    Tutar ikinci_;
};

int main() {
    std::printf("blok basladi\n");
    {
        Ciftlik c;
        std::printf("ciftlik kuruldu\n");
    }
    std::printf("blok bitti\n");
    return 0;
}
```

```text
blok basladi
yapici calisti kurus=1
yapici calisti kurus=2
ciftlik yapicisi calisti
ciftlik kuruldu
yikici calisti kurus=2
yikici calisti kurus=1
blok bitti
```

**SK7.** `Ciftlik`'in kendi yapıcı gövdesi çalışmadan önce `birinci_` ve `ikinci_`, sınıf
gövdesindeki bildirim sırasıyla (üye ilk değer listesindeki sıra değil — burada ikisi aynı
olduğu için fark görünmüyor, ama sıra her zaman bildirime göre belirlenir) kurulur; her
kurma kendi `Tutar` yapıcısını tetikler, bu yüzden `ciftlik yapicisi calisti` satırından
önce iki ayrı `yapici calisti` satırı görülür. `c` iç blok kapanırken yok olduğunda önce
`Ciftlik`'in kendi yıkıcısı (burada yazılmadığı için derleyici üretir, hiçbir çıktı basmaz),
sonra üyeleri **ters sırada** yıkılır: `ikinci_` önce, `birinci_` sonra. Kurma ile yıkım
birbirinin aynasıdır.

M10/K02'de (Rust) bir değerin kapsam dışına çıkışı `Drop` çalıştırıyordu; C++'ın yıkıcısı
aynı fikri karşılar, ama tetiklenme kuralları farklıdır ve bu ders o karşılaştırmayı
derinleştirmez.

Bildirim sırasının bağlayıcı olması, üye ilk değer listesinin **yazılma** sırasını görmezden
gelmesi anlamına gelir — bazı derleyiciler bir uyarı olarak listedeki sıranın bildirim
sırasıyla eşleşmediğini bildirir, çünkü bu iki sıranın farklı olması okuyucuyu yanıltabilir:
liste `ikinci_(2), birinci_(1)` sırasıyla yazılsa bile kurulma sırası yine `birinci_` önce
olurdu, çünkü sınıf gövdesinde `birinci_` önce bildirilmiştir. `Ciftlik` bu ders için listeyi
bildirim sırasıyla aynı yazar, bu yüzden iki sıra çakışır ve karışıklık doğmaz — ama kural
her zaman bildirim sırasıdır, listenin yazılış sırası değil.

Ters sıra yıkımın bir başka sonucu, bir üyenin yapıcısı bir öncekinin kurduğu bir kaynağa
güvenle kullanabilmesidir: `ikinci_` kurulurken `birinci_` zaten tam kurulmuştur, çünkü
bildirim sırasında ondan öncedir. Aynı güvence yıkımda tersine işler: `ikinci_` yıkılırken
`birinci_` henüz yıkılmamıştır, bu yüzden `ikinci_`'nin yıkıcısı gerekirse `birinci_`'ye
hâlâ güvenle erişebilir. Bu simetri, bir sonraki dersin konusu olan RAII'nin (Resource
Acquisition Is Initialization) üzerine kurulduğu temeldir: bir kaynağı tutan üye, onu
tutan nesnenin dışına çıkmadan önce yıkılmaz.

## Yapıcıların Birbirini Çağırması

Bir sınıfın birden çok yapıcısı olduğunda, bu yapıcılar arasında kod tekrarını önlemek için
bir yapıcı diğerini **devrederek** (delegating constructor) çağırabilir: `Tutar() :
Tutar(0) {}` yazmak, argümansız çağrıldığında işi tek-bağımsız-değişkenli yapıcıya
devreden bir yapıcı tanımlar. Devir, üye ilk değer listesinde sınıfın kendi adını çağırarak
yazılır — `Tutar(0)` burada başka bir üyenin değil, sınıfın kendisinin bir yapıcısını
çağırır. Devredilen yapıcı tam olarak çalışır (kendi gövdesi dahil) ve devreden yapıcının
gövdesi ondan sonra çalışır. `Tutar` bu dersin kapsamında devir kullanmaz — tek yapıcısı
vardır — ama bu teknik, birden çok yapıcı arasında ortak kurma mantığını tek bir yerde
tutmanın standart yoludur; ilk değer listesinde üye kurmakla karıştırılmamalıdır, çünkü
biri sınıfın kendi adını, diğeri bir üyenin adını çağırır.

## Varsayılan Yapıcı ve Varsayılan Değerler

`Tutar` argüman almayan bir yapıcı yazmaz, çünkü bir tutarın her zaman bir başlangıç
değeriyle kurulmasını ister — `Tutar t;` yazmak bu sınıf için derlenmez, çünkü tek yapıcı
bir `int` ister. Bir sınıf hiçbir yapıcı yazmazsa derleyici argüman almayan bir
**varsayılan yapıcı** üretir; bu üretilen yapıcı her veri üyesini kendi varsayılan değeriyle
kurar — sınıf tipindeki üyeler kendi varsayılan yapıcılarını çalıştırır, `int` gibi temel
tipler ise (üye bildiriminde bir ilk değer verilmemişse) **kurulmamış** kalır, yani rastgele
bir bellek değeri taşır. Bu, C'den gelen bir davranıştır ve C++'ta değişmemiştir: `Ciftlik`
gibi yalnız sınıf tipinde üyesi olan bir sınıfın varsayılan yapıcısı güvenlidir, çünkü her
üye kendi yapıcısını çalıştırır; ama `int miktar_;` gibi bir üye ilk değersiz bırakılırsa
varsayılan yapıcı onu kurulmamış bırakır. Bu kursta yazılan sınıflar, temel tipteki her
üyeye ya bildirimde (`int miktar_ = 0;`) ya da üye ilk değer listesinde açık bir başlangıç
değeri verir; kurulmamış bir üyeyi okumak da tanımsız davranıştır ve koşturulmaz.

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

Bu dersin ölçtüğü ifade — `goster(5)` içindeki örtük kurulan `Tutar` — **geçici**
sınıfındadır: adı yoktur, `goster(5);` ifadesinin sonunda yok olur. Ama geçicinin ömrü her
zaman bu kadar kısa kalmaz: bir geçici, `const` bir referansa bağlanırsa referansın ömrüne
uzar. `const Tutar& r = Tutar(7);` yazılsaydı, sağ taraftaki geçici normalde ifade
bitiminde yok olurdu, ama `r`'ye bağlandığı için ömrü `r`'nin kapsamının sonuna kadar
uzatılır — derleyici bunu otomatik yapar, programcının bir şey yazması gerekmez. Bu
uzatma yalnız `const` referanslar (ve bu kursun kapsamı dışındaki rvalue referanslar) için
geçerlidir; `Tutar& r = Tutar(7);` yazmak derlenmez, çünkü `const` olmayan bir referans bir
geçiciye bağlanamaz. Referansın kendisi bir başka geçiciye **yeniden** bağlanamaz olması —
bir referansın kurulduktan sonra hep aynı nesneyi göstermesi — bir sonraki konudaki
referanslar dersinin ölçtüğü şeydir.

Bu sınır, geçicilerin neden işlev çağrı zincirlerinde dikkatli kullanılması gerektiğini
açıklar: `goster(Tutar(5))` gibi bir çağrıda geçici yalnız `goster`'in çalıştığı ifade
boyunca yaşar; geçiciye ait bir işaretçi ya da `const` olmayan bir referans bu ifadeden
dışarı taşınırsa, ifade bittikten sonra o işaretçi ya da referans **sarkan** (dangling) hâle
gelir — gösterdiği bellek artık geçerli değildir. `Tutar`'ın `kurus()` işlevinin bir `int`
döndürmesi, `const Tutar&` ya da `Tutar*` değil, tam olarak bu riski taşımamak içindir:
`int` bir değer olarak kopyalanır, geçicinin kendisi yok olsa da kopyalanan değer geçerli
kalır.

Bu üç kural — örtük kurmanın geçici ürettiği, bildirim sırasının kurmayı ve yıkımı
belirlediği, `const` referansın geçicinin ömrünü uzatabildiği — bir arada bir nesnenin
"var olmak" ile "adlandırılmış olmak"ın aynı şey olmadığını gösterir. `goster(5)` içindeki
`Tutar` hiçbir değişkene atanmadan kurulur, yapıcısı çalışır, kullanılır, yıkıcısı çalışır;
bu tüm süreç boyunca hiçbir isim ona işaret etmez. Bir sonraki dersin RAII'si tam olarak bu
gözlemi kullanır: bir kaynağı serbest bırakmak için bir nesnenin adlandırılmış olması
gerekmez, yalnız yaşam süresinin sonuna gelmesi yeterlidir — derleyici o anı, adı olsun ya
da olmasın, her zaman bilir.

## Özet

- Bu dersin ölçtüğü ifade **geçici** sınıfındadır: `goster(5)` içinde örtük kurulan `Tutar`
  adsızdır ve `goster(5);` ifadesinin sonunda yok olur.
- Bir yapıcı sınıfla aynı adı taşır, bir yıkıcı `~` önekiyle yazılır; yıkıcı bağımsız
  değişken almaz ve bindirilemez.
- Tek argümanlı bir yapıcı örtük tip dönüşümüne izin verir; `explicit` bunu
  engelleyip yalnız açık kurmaya izin verir.
- Üye ilk değer listesi üyeleri **bildirim sırasıyla** kurar; yıkım bunun **tersi**
  sırada olur.
- `const` bir referansa bağlanan bir geçicinin ömrü, referansın kapsamına kadar uzatılır.

## Sonraki Adım

Bu ders bir nesnenin ne zaman kurulduğunu ve yok olduğunu ölçtü; bir sonraki ders bu
bilgiyi bir kaynağı (bellek, dosya tanıtıcısı gibi) güvenle serbest bırakmak için kullanır
— yıkıcının bir üyeyi nasıl bıraktığını, koruyucunun kendisiyle içindeki üyeyi ayırarak
ölçer.
