Menu
CoddyTech

Aturan Tiga, Lima, dan Nol

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 25 dari 104.

Saat class-mu mengelola sumber daya seperti memori dinamis, kamu sudah belajar bahwa kamu memerlukan destructor, copy constructor, dan move constructor khusus. Namun, ada prinsip panduan yang membantumu menentukan special member function mana yang perlu diimplementasikan: Rule of Three, Five, and Zero.

Aturan Tiga menyatakan: jika kamu mendefinisikan salah satu dari tiga hal ini, kamu sebaiknya mendefinisikan ketiganya:

  • Destruktor
  • Konstruktor salin
  • Operator penugasan salin

Rule of Five memperluas hal ini untuk C++ modern dengan menambahkan operasi pemindahan:

  • Destruktor
  • Konstruktor salin
  • Operator penugasan salin
  • Konstruktor pindah
  • Operator penugasan pindah
class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    
    ~Buffer() { delete[] data; }                          // 1. Destruktor
    Buffer(const Buffer& other);                          // 2. Konstruktor penyalin
    Buffer& operator=(const Buffer& other);               // 3. Penugasan salin
    Buffer(Buffer&& other) noexcept;                      // 4. Konstruktor pemindah
    Buffer& operator=(Buffer&& other) noexcept;           // 5. Penugasan pindah
};

Kedua operator penugasan mengikuti satu pola: cegah penugasan ke diri sendiri, lepaskan sumber daya lama, ambil sumber daya baru, lalu kembalikan *this:

Buffer& Buffer::operator=(const Buffer& other) {   // penugasan salin
    if (this != &other) {
        delete[] data;
        size = other.size;
        data = new int[size];
        std::copy(other.data, other.data + size, data);
    }
    return *this;
}

Buffer& Buffer::operator=(Buffer&& other) noexcept {   // penugasan pindah
    if (this != &other) {
        delete[] data;
        data = other.data;
        size = other.size;
        other.data = nullptr;
        other.size = 0;
    }
    return *this;
}

Rule of Zero adalah pendekatan paling sederhana: jika class-mu tidak mengelola resource secara langsung, jangan definisikan fungsi-fungsi ini. Biarkan compiler membuatnya, atau gunakan smart pointer dan container standar yang menangani resource untukmu.

class Player {
    std::string name;              // std::string mengelola memorinya sendiri
    std::vector<int> scores;       // std::vector mengelola sumber dayanya sendiri
public:
    Player(std::string n) : name(n) {}
    // Tidak perlu fungsi destructor, copy, atau move!
};

Mengikuti aturan ini mencegah bug seperti penghapusan ganda, kebocoran memori, dan pointer menggantung yang terjadi ketika beberapa operasi didefinisikan, tetapi operasi lainnya tidak tersedia.

challenge icon

Tantangan

Mudah

Mari buat class TextBuffer yang mengikuti Aturan Lima: mengimplementasikan kelima fungsi anggota khusus untuk mengelola data karakter yang dialokasikan secara dinamis dengan benar. Ini akan menunjukkan cara operasi penyalinan dan pemindahan bekerja bersama untuk membuat class yang tangguh dan mengelola resource.

Kamu akan membuat dua file untuk mengatur kodemu:

  • TextBuffer.h: Definisikan class TextBuffer yang menyimpan teks dalam array karakter yang dialokasikan secara dinamis. Class-mu memerlukan:
    • Anggota privat: pointer char* bernama data untuk konten teks, dan size_t length untuk panjang string (tidak termasuk terminator null)
    • Konstruktor berparameter yang menerima C-string (const char*), mengalokasikan memori, menyalin konten, dan mencetak "TextBuffer created: <text>"
    • Destructor yang membebaskan memori (jika tidak null) dan mencetak "TextBuffer destroyed"
    • Copy constructor yang melakukan salinan mendalam dan mencetak "TextBuffer copied"
    • Copy assignment operator yang menangani penugasan ke diri sendiri, membersihkan data yang ada, melakukan salinan mendalam, dan mencetak "TextBuffer copy-assigned". Kembalikan *this
    • Move constructor (ditandai dengan noexcept) yang memindahkan kepemilikan dan mencetak "TextBuffer moved". Biarkan sumber dalam keadaan kosong yang valid
    • Move assignment operator (ditandai dengan noexcept) yang menangani penugasan ke diri sendiri, membersihkan data yang ada, memindahkan kepemilikan, dan mencetak "TextBuffer move-assigned". Kembalikan *this
    • Method getText() yang mengembalikan teks tersimpan (kembalikan string kosong "" jika data null)
    • Method getLength() yang mengembalikan panjangnya
  • main.cpp: Tunjukkan kelima fungsi anggota khusus saat digunakan. Baca string teks dari input, lalu:
    • Buat TextBuffer bernama original dengan teks input
    • Buat copied menggunakan copy constructor dari original
    • Buat another dengan teks "Temporary"
    • Gunakan copy assignment: another = original
    • Buat moved dengan melakukan move construction dari original menggunakan std::move()
    • Buat target dengan teks "Target"
    • Gunakan move assignment: target = std::move(copied)
    • Cetak "--- Final State ---"
    • Cetak "original: <text> (length: <len>)" untuk setiap buffer: original, copied, moved, another, target

Setelah pemindahan, object sumber (original dan copied) seharusnya menampilkan teks kosong dengan panjang 0, sementara object tujuan menyimpan data yang dipindahkan. Ini menunjukkan Aturan Lima saat digunakan: kelima fungsi bekerja bersama untuk memastikan pengelolaan resource yang aman.

Sertakan <cstring> untuk fungsi string seperti strlen dan strcpy, serta <utility> untuk std::move().

Coba sendiri

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

using namespace std;

int main() {
    string input;
    getline(cin, input);

    // TODO: Buat TextBuffer bernama 'original' dengan teks input

    // TODO: Buat 'copied' menggunakan konstruktor penyalinan dari 'original'

    // TODO: Buat 'another' dengan teks "Temporary"

    // TODO: Gunakan penugasan salin: another = original

    // TODO: Buat 'moved' menggunakan konstruktor pemindahan dari 'original' dengan std::move()

    // TODO: Buat 'target' dengan teks "Target"

    // TODO: Gunakan penugasan pindah: target = std::move(copied)

    // TODO: Cetak "--- Final State ---"

    // TODO: Cetak keadaan setiap buffer dalam format ini:
    // "original: <text> (length: <len>)"
    // Cetak untuk: original, copied, moved, another, target

    return 0;
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler C++ online