C++'ta Akıllı İşaretçiler
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 15 / 104.
Akıllı işaretçiler (smart pointers), yığın (heap) belleğini sizin için otomatik olarak yöneten sarmalayıcı sınıflardır. İşaretçi kapsam dışına çıktığında belleği temizleyerek manuel delete çağrılarına olan ihtiyacı ortadan kaldırırlar.
Akıllı işaretçileri kullanmak için <memory> başlığını dahil edin.
unique_ptr - münhasır sahiplik. Bir kaynağa aynı anda yalnızca bir işaretçi sahip olabilir.
#include <memory>
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // Normal bir işaretçi gibi kullanın
// Kopyalanamaz, ancak sahiplik devredilebilir
std::unique_ptr<Player> player2 = std::move(player);
// player artık nullptr'dirshared_ptr - paylaşılan sahiplik. Birden fazla işaretçi aynı kaynağa sahip olabilir. Son sahip yok edildiğinde bellek serbest bırakılır.
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // Her ikisi de kaynağa sahiptir
std::cout << p1.use_count(); // 2 yazdırırweak_ptr - bir shared_ptr'nin sahiplik yapmayan gözlemcisidir. Döngüsel referansları (circular references) kırmak için yararlıdır.
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // shared_ptr'a dönüştür
locked->attack();
}Tekil sahiplik için varsayılan olarak unique_ptr kullanın. Birden fazla nesnenin bir kaynağı paylaşması gerektiğinde shared_ptr kullanın. Yaşam süresini uzatmadan gözlemlemek için weak_ptr kullanın.
Ham new yerine make_unique ve make_shared kullanmayı tercih edin.
Görev
KolayAkıllı işaretçilerin (smart pointers) farklı sahiplik modellerini gösteren bir belge paylaşım sistemi oluşturalım. unique_ptr'ın özel sahipliği nasıl zorunlu kıldığını, shared_ptr'ın birden fazla sahibe nasıl izin verdiğini ve weak_ptr'ın yaşam süresini etkilemeden nasıl gözlem yapabildiğini göreceksiniz.
Kodunuzu düzenlemek için iki dosya oluşturacaksınız:
Document.h: Paylaşılabilir bir belgeyi temsil eden birDocumentsınıfı tanımlayın. Şunlara sahip olmalıdır:- Özel (private) bir
titleözniteliği (string) - Bir başlık alan ve
"Document created: <title>"yazdıran bir yapıcı (constructor) "Document deleted: <title>"yazdıran bir yıkıcı (destructor)- Başlığı döndüren bir
getTitle()metodu
- Özel (private) bir
main.cpp: Girişten bir belge başlığı okuyarak her üç akıllı işaretçi türünü de gösterin, ardından:- Giriş başlığıyla bir Document'a
unique_ptroluşturun "Unique owner: <title>"yazdırınstd::movekullanarak sahipliği başka birunique_ptr'a aktarın"Ownership transferred"yazdırın"SharedDoc"başlığıyla yeni bir Document'ashared_ptroluşturun- Aynı belgeyi işaret eden ikinci bir
shared_ptroluşturun use_count()kullanarak"Shared owners: <count>"yazdırın- Paylaşılan işaretçilerden birinden bir
weak_ptroluşturun - Zayıf işaretçi aracılığıyla belgeye erişmek için
lock()kullanın ve"Weak access: <title>"yazdırın
- Giriş başlığıyla bir Document'a
Akıllı işaretçiler için <memory> kütüphanesini dahil etmeyi unutmayın. Akıllı işaretçilerinizi oluşturmak için std::make_unique ve std::make_shared kullanın. Yıkıcı mesajları, programın sonunda her belgenin ne zaman otomatik olarak temizlendiğini görmenize yardımcı olacaktır.
Başlık dosyanızı main.cpp içinde #include "Document.h" kullanarak dahil edin.
Kopya kağıdı
Akıllı işaretçiler (smart pointers), yığın (heap) belleğini otomatik olarak yöneten sarmalayıcı sınıflardır. Bunları kullanmak için <memory> başlık dosyasını dahil edin.
unique_ptr
Özel sahiplik - bir kaynağa aynı anda yalnızca bir işaretçi sahip olabilir:
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // Normal bir işaretçi gibi kullanın
// Sahipliği std::move ile aktarın
std::unique_ptr<Player> player2 = std::move(player);
// player artık nullptr'dirshared_ptr
Paylaşımlı sahiplik - birden fazla işaretçi aynı kaynağa sahip olabilir. Bellek, son sahip yok edildiğinde serbest bırakılır:
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // Her ikisi de kaynağa sahiptir
std::cout << p1.use_count(); // 2 yazdırırweak_ptr
Bir shared_ptr'nin sahiplik içermeyen gözlemcisidir. Döngüsel referansları kırmak için kullanışlıdır:
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // shared_ptr'ye dönüştür
locked->attack();
}En iyi uygulamalar: Tekil sahiplik için varsayılan olarak unique_ptr kullanın. Birden fazla nesnenin bir kaynağı paylaşması gerektiğinde shared_ptr kullanın. Yaşam süresini uzatmadan gözlemlemek için weak_ptr kullanın. Ham new yerine make_unique ve make_shared kullanmayı tercih edin.
Kendin dene
#include <iostream>
#include <memory>
#include <string>
#include "Document.h"
using namespace std;
int main() {
string inputTitle;
cin >> inputTitle;
// TODO: inputTitle ile bir Document için unique_ptr oluşturun
// std::make_unique kullanarak
// TODO: "Unique owner: <title>" yazdırın
// TODO: std::move kullanarak sahipliği başka bir unique_ptr nesnesine devredin
// TODO: "Ownership transferred" yazdırın
// TODO: "SharedDoc" başlıklı yeni bir Document için shared_ptr oluşturun
// std::make_shared kullanarak
// TODO: Aynı belgeyi işaret eden ikinci bir shared_ptr oluşturun
// TODO: use_count() kullanarak "Shared owners: <count>" yazdırın
// TODO: Paylaşılan işaretçilerden birinden bir weak_ptr oluşturun
// TODO: weak_ptr üzerinden belgeye erişmek için lock() kullanın
// ve "Weak access: <title>" yazdırın
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic Konteyner