Menu
Coddy logo textTech

Üç / Beş / Sıfır Kuralı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 25 / 104.

Sınıfınız dinamik bellek gibi kaynakları yönettiğinde, özel bir yıkıcı, kopya oluşturucu ve taşıma oluşturucuya ihtiyaç duyduğunuzu öğrenmişsinizdir. Ancak hangi özel üye işlevlerini uygulayacağınıza karar vermenize yardımcı olan bir yol gösterici ilke vardır: Üç, Beş ve Sıfır Kuralı.

Üç Kuralı şunu belirtir: Bu üç öğeden herhangi birini tanımlarsanız, üçünü de tanımlamalısınız:

  • Yıkıcı
  • Kopya oluşturucu
  • Kopya atama işleci

Rule of Five, taşıma işlemlerini ekleyerek bunu modern C++ için genişletir:

  • Yıkıcı
  • Kopya oluşturucu
  • Kopya atama işleci
  • Taşıma oluşturucusu
  • Taşıma atama işleci
class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    
    ~Buffer() { delete[] data; }                          // 1. Yıkıcı
    Buffer(const Buffer& other);                          // 2. Kopya kurucu
    Buffer& operator=(const Buffer& other);               // 3. Kopya atama
    Buffer(Buffer&& other) noexcept;                      // 4. Taşıma kurucu
    Buffer& operator=(Buffer&& other) noexcept;           // 5. Taşıma atama
};

Sıfır Kuralı en basit yaklaşımdır: sınıfınız kaynakları doğrudan yönetmiyorsa bu işlevlerden hiçbirini tanımlamayın. Bunları derleyicinin oluşturmasına izin verin veya kaynakları sizin için yöneten akıllı işaretçiler ve standart kapsayıcılar kullanın.

class Player {
    std::string name;              // std::string kendi belleğini yönetir
    std::vector<int> scores;       // std::vector kendi kaynaklarını yönetir
public:
    Player(std::string n) : name(n) {}
    // Yıkıcı, kopya veya taşıma fonksiyonlarına gerek yok!
};

Bu kurallara uymak, bazı işlemler tanımlanmış ancak diğerleri eksik olduğunda ortaya çıkan çift silme, bellek sızıntıları ve sarkan işaretçiler gibi hataları önler.

challenge icon

Görev

Kolay

Dinamik olarak ayrılmış karakter verilerini düzgün şekilde yönetmek için beş özel üye işlevin tamamını uygulayarak Rule of Five kurallarını izleyen bir TextBuffer sınıfı oluşturalım. Bu, sağlam ve kaynak yöneten bir sınıf oluşturmak için kopyalama ve taşıma işlemlerinin birlikte nasıl çalıştığını gösterecektir.

Kodunuzu düzenlemek için iki dosya oluşturacaksınız:

  • TextBuffer.h: Metni dinamik olarak ayrılmış bir karakter dizisinde depolayan bir TextBuffer sınıfı tanımlayın. Sınıfınız şunlara sahip olmalıdır:
    • Özel üyeler: metin içeriği için char* adlı bir data işaretçisi ve dize uzunluğu için (null sonlandırıcı dahil olmayan) bir size_t length
    • Bir C dizesi (const char*) alan, bellek ayıran, içeriği kopyalayan ve "TextBuffer created: <text>" yazdıran parametreli kurucu
    • Belleği (null değilse) serbest bırakan ve "TextBuffer destroyed" yazdıran bir yıkıcı
    • Derin kopyalama gerçekleştiren ve "TextBuffer copied" yazdıran bir kopya kurucusu
    • Kendine atamayı ele alan, mevcut verileri temizleyen, derin kopyalama gerçekleştiren ve "TextBuffer copy-assigned" yazdıran bir kopya atama işleci. *this döndürün
    • Sahipliği devreden ve noexcept yazdıran, "TextBuffer moved" ile işaretlenmiş bir taşıma kurucusu. Kaynağı geçerli ve boş bir durumda bırakın
    • Kendine atamayı ele alan, mevcut verileri temizleyen, sahipliği devreden ve noexcept yazdıran, "TextBuffer move-assigned" ile işaretlenmiş bir taşıma atama işleci. *this döndürün
    • Depolanan metni döndüren bir getText() yöntemi (data null ise boş dize "" döndürün)
    • Uzunluğu döndüren bir getLength() yöntemi
  • main.cpp: Beş özel üye işlevin tamamını çalışırken gösterin. Girdiden bir metin dizesi okuyun, ardından:
    • Girdi metniyle TextBuffer adlı bir original oluşturun
    • copied kaynağındaki kopya kurucusunu kullanarak original oluşturun
    • another metniyle "Temporary" oluşturun
    • Kopya atamasını kullanın: another = original
    • moved kullanarak original kaynağından taşıma kurucusuyla std::move() oluşturun
    • target metniyle "Target" oluşturun
    • Taşıma atamasını kullanın: target = std::move(copied)
    • "--- Final State ---" yazdırın
    • Her arabellek için — original, copied, moved, another, target — "original: <text> (length: <len>)" yazdırın

Taşıma işlemlerinden sonra kaynak nesneler (original ve copied) uzunlukları 0 olan boş metin göstermeli, hedef nesneler ise aktarılan verileri içermelidir. Bu, Rule of Five kurallarını uygulamalı olarak gösterir: güvenli kaynak yönetimi sağlamak için beş işlevin tamamı birlikte çalışır.

<cstring> ve strlen gibi dize işlevleri için strcpy, <utility> için de std::move() ekleyin.

Kendin dene

#include <iostream>
#include <string>
#include <utility>
#include "TextBuffer.h"

using namespace std;

int main() {
    string input;
    getline(cin, input);

    // TODO: Girdi metniyle 'original' adında bir TextBuffer oluştur

    // TODO: 'original' üzerinden kopya yapıcı kullanarak 'copied' oluştur

    // TODO: "Temporary" metniyle 'another' oluştur

    // TODO: Kopya atama kullan: another = original

    // TODO: std::move() kullanarak 'original'dan taşıma yapıcısıyla 'moved' oluştur

    // TODO: "Target" metniyle 'target' oluştur

    // TODO: Taşıma ataması kullan: target = std::move(copied)

    // TODO: "--- Final State ---" yazdır

    // TODO: Her arabelleğin durumunu şu formatta yazdır:
    // "original: <text> (length: <len>)"
    // Şunlar için yazdır: original, copied, moved, another, target

    return 0;
}
quiz iconKendini test et

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

Kendi başına pratik yap: Online C++ derleyicisi