Menu
Coddy logo textTech

Taşıma Yapıcısı

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

Bir taşıma kurucusu, kaynakları kopyalamak yerine geçici bir nesneden aktarır. Kopya kurucusu verileri çoğaltırken, taşıma kurucusu kaynakları “çalak” kaynak nesneyi geçerli ancak boş bir durumda bırakır. Bu, kaynak nesne zaten yok edilmek üzereyken maliyetli derin kopyaları önler.

Taşıma kurucusu, && ile gösterilen bir rvalue başvurusu alır:

class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    
    // Taşıma kurucusu
    Buffer(Buffer&& other) noexcept {
        data = other.data;       // İşaretçiyi çal
        size = other.size;
        other.data = nullptr;    // Kaynağı geçerli bir durumda bırak
        other.size = 0;
    }
    
    ~Buffer() { delete[] data; }
};

Kopyalamadan temel fark: yeni bellek tahsis etmeyiz. Sadece mevcut belleğin sahipliğini alırız ve kaynağın işaretçisini nullptr olarak ayarlarız, böylece yıkıcısı verilerimizi silmez.

Taşıma kurucuları, geçici nesnelerden başlatma yapıldığında veya std::move() kullanıldığında çağrılır:

Buffer createBuffer() {
    return Buffer(1000);    // Taşıma kurucusu kullanıldı (dönüş değeri)
}

Buffer b1(1000);
Buffer b2(std::move(b1));   // Açık taşıma - b1 artık boş

Taşıma kurucularını mümkün olduğunda noexcept olarak işaretleyin. Bu, işlemin istisna oluşturmayacağını derleyiciye bildirerek std::vector gibi kapsayıcılarda önemli optimizasyonların etkinleştirilmesini sağlar.

challenge icon

Görev

Kolay

Taşıma kurucularının kaynakların sahipliğini nasıl verimli bir şekilde aktardığını gösteren bir veri paketi sistemi oluşturalım. Dinamik olarak ayrılmış bir bayt dizisini yöneten bir DataPacket sınıfı oluşturacak ve verileri kopyalamak yerine "çalan" bir taşıma kurucusu uygulayacaksın.

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

  • DataPacket.h: Tamsayı verilerinden oluşan bir yükü yöneten bir DataPacket sınıfı tanımla. Sınıfında şunlar bulunmalı:
    • Özel üyeler: tamsayı dizisine yönelik bir işaretçi (payload), eleman sayısı için bir size ve paketi tanımlamak için bir packetId (string)
    • Bir paket kimliği ve boyut alan, diziyi ayıran ve 0'dan size-1'e kadar değerlerle dolduran parametreli bir kurucu. "Packet <id> created with size <size>" yazdır
    • Kaynak nesneden payload sahipliğini aktaran ve noexcept olarak işaretlenmiş bir taşıma kurucusu. "Packet <id> moved" yazdır. Kaynağı geçerli ve boş bir durumda (nullptr, size 0) bırakmayı unutma
    • İşaretçi null değilse belleği serbest bırakan ve "Packet <id> destroyed" yazdıran bir yıkıcı
    • Geçerli boyutu döndüren bir getSize() metodu
    • Paket kimliğini döndüren bir getId() metodu
    • Payload içindeki tüm elemanların toplamını döndüren bir getSum() metodu (payload null ise 0 döndür)
  • main.cpp: Girdiden bir paket kimliği ve boyut okuyarak taşıma oluşturmayı göster. Ardından:
    • Girdi değerleriyle DataPacket adlı bir original oluştur
    • "Original - ID: <id>, Size: <size>, Sum: <sum>" yazdır
    • transferred kullanarak original'dan taşıma yapıp std::move() adlı yeni bir paket oluştur
    • "After move:" yazdır
    • "Original - ID: <id>, Size: <size>, Sum: <sum>" yazdır
    • "Transferred - ID: <id>, Size: <size>, Sum: <sum>" yazdır

Girdi biçimi şöyle olacaktır:

  • İlk satır: paket kimliği (string)
  • İkinci satır: boyut (tamsayı)

Taşıma işleminden sonra, verileri aktarıldığı için özgün paketin boyutu 0 ve toplamı 0 olmalı; taşınan paket ise tüm özgün verilere sahip olmalı. Bu, işaretçi sahipliğini basitçe aktararak taşıma semantiğinin maliyetli derin kopyaları nasıl önlediğini gösterir.

Başlık dosyanı #include "DataPacket.h" kullanarak main.cpp dosyasına dahil et ve <utility> için std::move() eklemeyi unutma.

Kendin dene

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

using namespace std;

int main() {
    // Girdiyi oku
    string packetId;
    int size;
    cin >> packetId;
    cin >> size;

    // TODO: Giriş değerleriyle 'original' adında bir DataPacket oluşturun

    // TODO: "Original - ID: <id>, Size: <size>, Sum: <sum>" yazdırın

    // TODO: original nesnesini taşıyarak 'transferred' adında yeni bir paket oluşturun
    // İpucu: std::move() kullanın

    // TODO: "After move:" yazdırın

    // TODO: "Original - ID: <id>, Size: <size>, Sum: <sum>" yazdırın

    // TODO: "Transferred - ID: <id>, Size: <size>, Sum: <sum>" yazdırın

    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