Penerusan Sempurna
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 84 dari 104.
Saat menulis fungsi template yang menerima argumen dan meneruskannya ke fungsi lain, muncul masalah: bagaimana kamu mempertahankan apakah argumen aslinya berupa lvalue atau rvalue? Perfect forwarding mengatasi masalah ini dengan meneruskan argumen persis seperti saat diterima, dengan mempertahankan kategori nilainya.
Bahan utamanya adalah referensi penerusan (ditulis sebagai T&& dalam konteks templat) dan std::forward. Referensi penerusan dapat terikat pada lvalue maupun rvalue, dan std::forward secara kondisional meng-cast argumen kembali ke tipe aslinya:
#include <iostream>
#include <utility>
void process(int& x) { std::cout << "lvalue: " << x << "\n"; }
void process(int&& x) { std::cout << "rvalue: " << x << "\n"; }
template<typename T>
void wrapper(T&& arg) {
process(std::forward<T>(arg));
}
int main() {
int n = 10;
wrapper(n); // Memanggil process(int&), lvalue tetap terjaga
wrapper(20); // Memanggil process(int&&), rvalue tetap terjaga
}Tanpa std::forward, parameter bernama selalu berupa lvalue di dalam fungsi, meskipun yang diteruskan adalah rvalue. Hal ini akan membuat semantik pemindahan tidak berfungsi dengan benar saat meneruskan parameter ke konstruktor atau fungsi lain.
Penerusan sempurna sangat penting untuk menulis fungsi factory, wrapper class, dan kode generik apa pun yang perlu membuat object atau memanggil fungsi sambil mempertahankan maksud pemanggil terkait operasi move dan copy.
Tantangan
MudahMari buat fungsi factory yang menunjukkan perfect forwarding dengan membangun object sambil mempertahankan kategori nilai argumen yang diberikan kepadanya. Kamu akan membuat fungsi generik make_object yang meneruskan argumen ke constructor class, memastikan bahwa lvalue disalin dan rvalue dipindahkan.
Kamu akan mengatur kodemu dalam tiga file:
Widget.h: Definisikan classWidgetyang mencatat cara menerima datanya.Widgetharus menyimpan nama bertipestd::stringdan nilai bertipeint. Buat dua constructor:- Satu yang menerima
const std::string&(referensi lvalue) danint: mencetakWidget constructed (copy): [name] - Satu yang menerima
std::string&&(referensi rvalue) danint: mencetakWidget constructed (move): [name]dan memindahkan string
Tambahkan juga method
display()yang mencetak[name]: [value].- Satu yang menerima
Factory.h: Buat fungsi factory perfect forwarding.Tulis fungsi template
make_objectyang menerima forwarding reference untuk nama danintbiasa untuk nilai. Gunakanstd::forwarduntuk meneruskan argumen nama ke constructorWidgetsambil mempertahankan kategori nilai aslinya.Fungsi tersebut harus mengembalikan
Widgetyang telah dibuat berdasarkan nilai.main.cpp: Baca dua input:- Sebuah nama (string)
- Sebuah nilai (bilangan bulat)
Tunjukkan perfect forwarding dengan membuat dua widget:
- Pertama, simpan nama dalam variabel lokal dan berikan ke
make_objectsebagai lvalue - Kedua, berikan string sementara (nama yang sama digabungkan dengan
"_temp") langsung kemake_objectsebagai rvalue
Setelah membuat setiap widget, panggil method
display()-nya.
Sebagai contoh, dengan input Gadget dan 42:
Widget constructed (copy): Gadget
Gadget: 42
Widget constructed (move): Gadget_temp
Gadget_temp: 42Dengan input Device dan 100:
Widget constructed (copy): Device
Device: 100
Widget constructed (move): Device_temp
Device_temp: 100Inti utamanya adalah fungsi make_object tidak mengetahui apakah ia menerima lvalue atau rvalue, tetapi dengan menggunakan std::forward, fungsi tersebut mempertahankan informasi itu saat memanggil constructor Widget. Dengan demikian, resolusi overload constructor dapat memilih versi yang sesuai, sehingga perpindahan dapat dilakukan secara efisien untuk nilai sementara, sementara variabel bernama disalin dengan aman.
Coba sendiri
#include <iostream>
#include <string>
#include "Widget.h"
#include "Factory.h"
using namespace std;
int main() {
// Baca input
string name;
int value;
cin >> name >> value;
// TODO: Buat widget pertama dengan meneruskan name sebagai lvalue
// Simpan name dalam variabel lokal, lalu teruskan ke make_object
// TODO: Panggil display() pada widget pertama
// TODO: Buat widget kedua dengan meneruskan string sementara sebagai rvalue
// Teruskan (name + "_temp") langsung ke make_object
// TODO: Panggil display() pada widget kedua
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 GenerikLatihan sendiri: Compiler C++ online