8.1 Sahiplik (Ownership) ve RAII Prensibi
Modern C++ mimarisinde bellek yönetimi, Kaynak Edinimi Başlatmadır (Resource Acquisition Is Initialization - RAII) prensibine dayanır. Bu prensibe göre, bir kaynağın (bellek, dosya, kilit) yaşam ömrü, bir nesnenin yaşam ömrüne bağlanır. Nesne yok edildiğinde, kaynak da Belirlenimci (Deterministic) bir şekilde serbest bırakılır.
Münhasır Sahiplik (Exclusive Ownership)
Bir kaynağın tek bir sahibi olduğu modeldir. Sahiplik devredilebilir (move) ancak kopyalanamaz. Temsilcisi: `std::unique_ptr`.
Paylaşımlı Sahiplik (Shared Ownership)
Bir kaynağın birden fazla sahibi olabildiği modeldir. Referans sayacı (Reference counting) ile yönetilir. Temsilcisi: `std::shared_ptr`.
8.2 Bellek Sahiplik Diyagramı
Şema 8.1: Akıllı İşaretçilerin (Smart Pointers) Bellek ve Kontrol Blok Yapısı
8.3 Uygulama: Modern Kaynak Yönetimi
#include <iostream>
#include <memory>
#include <vector>
class SensorData {
public:
SensorData() { std::cout << "Sensor aktif.\n"; }
~SensorData() { std::cout << "Sensor kapatildi.\n"; }
void veri_oku() const { std::cout << "Veri isleniyor...\n"; }
};
/**
* @brief Akademik Analiz: Sahiplik Devri (Ownership Transfer)
* MISRA C++:2023 Notu: 'new' ve 'delete' kullanımı yerine 'make_unique' tercih edilmelidir.
*/
void islem_merkezi(std::unique_ptr<SensorData> ptr) {
if (ptr) ptr->veri_oku();
} // ptr burada yok edilir, bellek OTOMATİK iade edilir.
int main() {
// 1. Münhasır Sahiplik (Exclusive Ownership)
auto sensor = std::make_unique<SensorData>();
// islem_merkezi(sensor); // HATA: unique_ptr kopyalanamaz!
islem_merkezi(std::move(sensor)); // Sahiplik devredildi (Move semantics).
// 2. Paylaşımlı Sahiplik (Shared Ownership)
std::shared_ptr<SensorData> ortak_sensor = std::make_shared<SensorData>();
{
std::shared_ptr<SensorData> ikinci_paydas = ortak_sensor;
std::cout << "Paydas sayisi: " << ortak_sensor.use_count() << "\n"; // 2
} // ikinci_paydas yok olur, sayaç 1'e iner.
return 0;
}
Mimarın Analizi:
`std::make_unique` ve `std::make_shared` kullanımı sadece sözdizimsel bir kolaylık değil, aynı zamanda İstisna Güvenliği (Exception Safety) için bir zorunluluktur. Necati Ergin'in vurguladığı gibi, `new` ifadesi sırasında bir istisna oluşursa, bellek sızıntısı riski doğar; ancak `make` fonksiyonları bu riski mimari olarak engeller.
Döngüsel Bağımlılık (Circular Dependency):
İki `shared_ptr` birbirini gösterirse, referans sayacı asla sıfıra inmez. Bu akademik açmazı çözmek için Zayıf İşaretçi (Weak Pointer - std::weak_ptr) kullanılır. `weak_ptr` sahiplik iddia etmez, sadece kaynağın varlığını gözlemler.
⚠️ Akıllı İşaretçi Yanılgıları
Çıplak İşaretçiden Birden Fazla unique_ptr Oluşturmak
Aynı ham adresi (raw pointer) iki farklı `unique_ptr`'a atamak, aynı belleğin iki kez silinmesine (double free) neden olur.
Çözüm: Ham adreslerle uğraşmak yerine daima `make_unique` kullanın.
shared_ptr Performans Maliyeti
Her `shared_ptr` kopyalandığında referans sayacı atomik olarak artırılır. Bu, yüksek başarımlı sistemlerde (HPC) gereksiz bir yük oluşturabilir.
İpucu: Sahiplik paylaşımı gerekmiyorsa daima `unique_ptr` tercih edin.
8.5 Bellek Yönetimi Testi
Soru: 'std::weak_ptr' kullanımının temel amacı nedir?
Pratik Görev (Telegram Challenge):
"trcpp-telegram topluluğunda 'Custom Deleter' konusu sıkça sorulur. Bir dosya işaretçisini (FILE*) yöneten ve dosya kapandığında otomatik olarak 'fclose' çağıran bir 'std::unique_ptr' yapısı tasarlayın."