Semantik Pemindahan & Rvalue
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 83 dari 104.
Dalam C++, setiap ekspresi adalah lvalue (memiliki identitas yang bertahan, dapat diambil alamatnya) atau rvalue (bersifat sementara dan akan segera dihapus). Memahami perbedaan ini membuka pemahaman tentang move semantics, sebuah optimasi ampuh yang menghindari penyalinan yang tidak perlu.
rvalue reference, yang dideklarasikan dengan &&, terikat secara khusus pada object sementara. Ini memungkinkan kamu "mengambil" sumber daya dari object yang akan segera hilang:
#include <iostream>
#include <utility>
class Buffer {
int* data;
size_t size;
public:
Buffer(size_t s) : data(new int[s]), size(s) {
std::cout << "Constructed\n";
}
// Konstruktor pemindahan mengambil alih sumber daya
Buffer(Buffer&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr; // Biarkan sumber tetap dalam keadaan valid
other.size = 0;
std::cout << "Moved\n";
}
~Buffer() { delete[] data; }
};
int main() {
Buffer b1(1000);
Buffer b2(std::move(b1)); // Memanggil konstruktor pemindahan
}Fungsi std::move sebenarnya tidak memindahkan apa pun, fungsi ini hanya meng-cast lvalue menjadi rvalue reference, yang menandakan bahwa kamu bersedia melepaskan resource object tersebut. Pemindahan yang sebenarnya terjadi di move constructor atau operator assignment move.
Semantik pemindahan meningkatkan performa secara drastis saat bekerja dengan object yang membutuhkan banyak sumber daya, seperti container atau string. Alih-alih menyalin data berukuran megabita secara mendalam, kamu cukup memindahkan kepemilikan pointer, sebuah operasi yang membutuhkan waktu konstan terlepas dari ukurannya.
Tantangan
MudahMari kita buat class DataBuffer yang mengelola sumber daya dan menunjukkan cara kerja semantik pemindahan. Kamu akan melihat bagaimana memindahkan sumber daya alih-alih menyalinnya dapat sangat meningkatkan efisiensi saat kepemilikan memori yang dialokasikan secara dinamis dialihkan.
Kamu akan menyusun kodemu dalam tiga file:
DataBuffer.h: Definisikan classDataBufferyang mengelola array integer yang dialokasikan secara dinamis.Class-mu harus memiliki anggota privat untuk pointer data (
int*), ukuran (size_t), dan nama (std::string) untuk membantu melacak buffer saat operasi berlangsung.Deklarasikan hal-hal berikut:
- Constructor yang menerima nama
std::stringdan ukuransize_t, mengalokasikan array, dan mencetak:[name] constructed with size [size] - Move constructor yang menerima referensi rvalue, mengambil alih sumber daya, dan mencetak:
[name] moved from [source_name](buffer yang menerima pemindahan menggunakan nama sumber) - Destructor yang mencetak
[name] destroyed(atauempty destroyedjika buffer dipindahkan) - Method
getSize()yang mengembalikan ukuran saat ini - Method
getName()yang mengembalikan nama buffer
Ingat untuk menandai move constructor-mu dengan
noexceptdan membiarkan object sumber dalam keadaan kosong yang valid (nullptr, size 0, name "empty").- Constructor yang menerima nama
DataBuffer.cpp: Implementasikan semua method yang dideklarasikan di header-mu. Saat destructor berjalan, hapus data hanya jika pointer-nya tidak null. Sertakan<iostream>untuk output.main.cpp: Baca dua input:- Nama untuk buffer-mu (string)
- Ukuran untuk buffer-mu (integer)
Buat
DataBufferdengan nama dan ukuran yang diberikan. Lalu buat buffer kedua dengan memindahkan isi buffer pertama menggunakanstd::move(). Setelah pemindahan, cetak keadaan kedua buffer:Original: [name] size=[size]New: [name] size=[size]
Sertakan
<utility>untukstd::move.
Contohnya, dengan input Alpha dan 100:
Alpha constructed with size 100
Alpha moved from Alpha
Original: empty size=0
New: Alpha size=100
Alpha destroyed
empty destroyedDengan input Buffer dan 50:
Buffer constructed with size 50
Buffer moved from Buffer
Original: empty size=0
New: Buffer size=50
Buffer destroyed
empty destroyedPerhatikan bagaimana move constructor mengalihkan kepemilikan memori yang dialokasikan tanpa menyalin data apa pun. Buffer asli dibiarkan dalam keadaan kosong tetapi valid, dan saat kedua buffer dihancurkan di akhir program, hanya buffer yang masih memiliki memori yang benar-benar menghapusnya.
Coba sendiri
#include <iostream>
#include <string>
#include <utility>
#include "DataBuffer.h"
int main() {
std::string name;
int size;
std::cin >> name;
std::cin >> size;
// TODO: Buat DataBuffer dengan nama dan ukuran yang diberikan
// TODO: Buat buffer kedua dengan memindahkan isi dari buffer pertama menggunakan std::move()
// TODO: Tampilkan keadaan kedua buffer:
// Asli: [name] size=[size]
// Baru: [name] size=[size]
return 0;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container Generik12Fitur Modern C++
Semantik Pemindahan & RvaluePenerusan SempurnaEkspresi Lambda secara Mendalamstd::function & std::bindconstexpr dan constevalPengikatan Terstrukturoptional, variant, anyLatihan sendiri: Compiler C++ online