Menu
Coddy logo textTech

Atama Operatörü Aşırı Yükleme

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

Kopyalama atama operatörü (=), mevcut bir nesneyi diğerine atadığınızda çağrılır. Kopyalama kurucusunun (yeni bir nesne oluşturan) aksine, atama operatörü halihazırda var olan ve öncelikle temizlenmesi gereken kaynaklara sahip olabilecek bir nesneyle çalışır.

class Buffer {
    int* data;
    size_t size;
    
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    ~Buffer() { delete[] data; }
    
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {              // 1. Kendi kendine atama kontrolü
            delete[] data;                  // 2. Mevcut kaynağı temizle
            size = other.size;              // 3. Veriyi kopyala
            data = new int[size];
            for (size_t i = 0; i < size; ++i)
                data[i] = other.data[i];
        }
        return *this;                       // 4. *this döndür
    }
};

Kendi kendine atama kontrolü (this != &other) kritiktir. Bu olmadan, b = b; veriyi kopyalamaya çalışmadan önce siler ve tanımsız davranışa neden olur.

Operatör, a = b = c; gibi zincirlemeyi etkinleştirmek için *this ifadesini referans yoluyla döndürür. Bu, yerleşik türlerin nasıl davrandığıyla eşleşir.

Kaynakları yöneten sınıflar için, genellikle hem kopyalama hem de taşıma atama operatörlerini uygulayacaksınız:

Buffer& operator=(Buffer&& other) noexcept {
    if (this != &other) {
        delete[] data;           // Mevcut kaynağı temizle
        data = other.data;       // Kaynağı çal
        size = other.size;
        other.data = nullptr;    // Kaynağı geçerli bir durumda bırak
        other.size = 0;
    }
    return *this;
}

Taşıma atama operatörü, kopyalamak yerine sahipliği aktarır ve vec[0] = createBuffer(); gibi işlemleri çok daha verimli hale getirir.

challenge icon

Görev

Kolay

Dinamik olarak ayrılmış bir karakter dizisini yöneten ve mevcut nesneler arasındaki atamayı düzgün şekilde gerçekleştiren bir DynamicString sınıfı oluşturalım. Bu, bellek sızıntıları veya sarkan işaretçiler olmadan dizi verilerini bir nesneden diğerine güvenli şekilde aktarmanız gereken pratik bir senaryodur.

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

  • DynamicString.h: Dinamik bellek kullanarak C stili bir dizi depolayan bir DynamicString sınıfı tanımlayın. Sınıfınız şunları yönetmelidir:
    • Dizi verisi için private bir char* işaretçisi
    • Uzunluk için private bir size_t
    • Bir const char* alan ve derin bir kopya oluşturan bir kurucu
    • Ayrılmış belleği düzgün şekilde serbest bırakan bir yıkıcı
    • Kendine atama korumasıyla derin kopyalama gerçekleştiren bir kopya atama operatörü
    • Sahipliği verimli şekilde aktaran bir taşıma atama operatörü
    • Dahili diziyi (const) döndüren bir c_str() yöntemi
    • Dizi uzunluğunu (const) döndüren bir length() yöntemi

    Kopya atama operatörünüz dört temel adımı izlemelidir: kendine atamayı kontrol etmek, mevcut kaynakları temizlemek, yeni veriyi kopyalamak ve *this döndürmek. Taşıma atama operatörü, kaynak nesnenin işaretçisini devralmalı ve kaynağı geçerli, boş bir durumda bırakmalıdır (uzunluğu 0 olan nullptr).

  • main.cpp: Girdiden üç dizi okuyun (her biri ayrı bir satırda). Üç adet DynamicString nesnesi oluşturun: ilk girdiyle str1, ikinci girdiyle str2 ve üçüncü girdiyle str3.

    Atama operatörlerinizi gösterin:

    1. Üç dizenin de başlangıç durumunu yazdırın
    2. Kopya atamasını kullanın: str1 = str2;
    3. Kopya atamasından sonra str1 ve str2'yi yazdırın (ikisi de aynı içeriğe sahip olmalıdır)
    4. Taşıma atamasını kullanın: str2 = std::move(str3);
    5. Taşıma atamasından sonra str2'yi ve str3'ün uzunluğunu yazdırın (taşındıktan sonra 0 olmalıdır)

    Çıktı biçimi:

    Initial:
    str1: <value>
    str2: <value>
    str3: <value>
    After copy (str1 = str2):
    str1: <value>
    str2: <value>
    After move (str2 = std::move(str3)):
    str2: <value>
    str3 length: 0

<cstring> ve strlen için strcpy kullanın. Taşıma atama operatörünüzü noexcept olarak işaretleyin. <utility> için main.cpp dosyasına std::move ekleyin. Başlık dosyanızda başlık koruyucularını kullanmayı unutmayın.

Kendin dene

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

using namespace std;

int main() {
    // Girdiden üç dize oku
    string input1, input2, input3;
    getline(cin, input1);
    getline(cin, input2);
    getline(cin, input3);

    // Üç DynamicString nesnesi oluştur
    DynamicString str1(input1.c_str());
    DynamicString str2(input2.c_str());
    DynamicString str3(input3.c_str());

    // TODO: Her üç dizenin başlangıç durumunu yazdır
    // Biçim:
    // Initial:
    // str1: <value>
    // str2: <value>
    // str3: <value>

    // TODO: Kopyalama atamasını kullan: str1 = str2;

    // TODO: Kopyalama atamasından sonra str1 ve str2'yi yazdır
    // Biçim:
    // After copy (str1 = str2):
    // str1: <value>
    // str2: <value>

    // TODO: Taşıma atamasını kullan: str2 = std::move(str3);

    // TODO: Taşımadan sonra str2'yi ve str3'ün uzunluğunu yazdır
    // Biçim:
    // After move (str2 = std::move(str3)):
    // str2: <value>
    // str3 length: 0

    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