Menu
CoddyTech

Aturan Tiga, Lima, dan Nol

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

Jika class-mu mengelola sumber daya seperti memori dinamis, kamu telah mempelajari bahwa kamu memerlukan destructor kustom, copy constructor, dan move constructor. Namun, ada prinsip panduan yang membantumu memutuskan 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 konsep ini untuk C++ modern dengan menambahkan operasi pemindahan:

  • Destructor
  • Konstruktor salin
  • Operator penugasan salin
  • Konstruktor pemindahan
  • Operator penugasan pemindahan
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 penyalinan
    Buffer& operator=(const Buffer& other);               // 3. Penugasan penyalinan
    Buffer(Buffer&& other) noexcept;                      // 4. Konstruktor pemindahan
    Buffer& operator=(Buffer&& other) noexcept;           // 5. Penugasan pemindahan
};

Kedua operator assignment mengikuti satu pola: cegah assignment ke diri sendiri, lepaskan resource lama, ambil resource 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 sumber daya secara langsung, jangan definisikan fungsi-fungsi ini. Biarkan compiler membuatnya, atau gunakan smart pointer dan container standar yang menangani sumber daya 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 yang menggantung, yang terjadi saat beberapa operasi didefinisikan, tetapi operasi lainnya tidak ada.

challenge icon

Tantangan

Mudah

Mari buat class TextBuffer yang mengikuti Rule of Five: menerapkan 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 menata kodemu:

  • TextBuffer.h: Definisikan class TextBuffer yang menyimpan teks dalam array karakter yang dialokasikan secara dinamis. Class-mu memerlukan:
    • Anggota private: 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>"
    • Destruktor yang membebaskan memori (jika tidak null) dan mencetak "TextBuffer destroyed"
    • Konstruktor salin yang melakukan penyalinan mendalam dan mencetak "TextBuffer copied"
    • Operator penugasan salin yang menangani penugasan ke diri sendiri, membersihkan data yang ada, melakukan penyalinan mendalam, dan mencetak "TextBuffer copy-assigned". Kembalikan *this
    • Konstruktor pindah (ditandai dengan noexcept) yang memindahkan kepemilikan dan mencetak "TextBuffer moved". Biarkan sumber dalam keadaan kosong yang valid
    • Operator penugasan pindah (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 yang disimpan (kembalikan string kosong "" jika data null)
    • Method getLength() yang mengembalikan panjang
  • 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 konstruktor salin dari original
    • Buat another dengan teks "Temporary"
    • Gunakan penugasan salin: another = original
    • Buat moved dengan membuatnya melalui konstruktor pindah dari original menggunakan std::move()
    • Buat target dengan teks "Target"
    • Gunakan penugasan pindah: 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, sedangkan object tujuan menyimpan data yang dipindahkan. Ini menunjukkan Rule of Five: 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 copy constructor dari 'original'

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

    // TODO: Gunakan copy assignment: another = original

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

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

    // TODO: Gunakan move assignment: 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