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.
Görev
KolayTaşı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 birDataPacketsı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 birsizeve paketi tanımlamak için birpacketId(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
noexceptolarak 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)
- Özel üyeler: tamsayı dizisine yönelik bir işaretçi (
main.cpp: Girdiden bir paket kimliği ve boyut okuyarak taşıma oluşturmayı göster. Ardından:- Girdi değerleriyle
DataPacketadlı biroriginaloluştur "Original - ID: <id>, Size: <size>, Sum: <sum>"yazdırtransferredkullanarakoriginal'dan taşıma yapıpstd::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 değerleriyle
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;
}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 KonteynerKendi başına pratik yap: Online C++ derleyicisi