🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Esercizi Regole 3-5 C++

Codegrind Team•Jul 12 2024

Ecco degli esercizi con soluzione per praticare l’utilizzo delle Rule of Three e Rule of Five in C++.

Rule of Three

Esercizio 1: Implementazione della Rule of Three

Creare una classe con costruttore di copia, operatore di assegnazione di copia e distruttore.
#include <iostream>

class MyClass {
private:
    int* data;
public:
    // Costruttore
    MyClass(int value) : data(new int(value)) {}

    // Costruttore di copia
    MyClass(const MyClass& other) : data(new int(*other.data)) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    // Operatore di assegnazione di copia
    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        *data = *other.data;
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    // Distruttore
    ~MyClass() {
        delete data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        std::cout << "Valore: " << *data << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1; // Costruttore di copia chiamato
    obj2 = obj1;         // Operatore di assegnazione di copia chiamato
    obj1.print();
    obj2.print();
    return 0;
}

Esercizio 2: Profondo contro copia superficiale

Implementare una copia superficiale e osservare i problemi di gestione della memoria.
#include <iostream>

class MyClass {
private:
    int* data;
public:
    MyClass(int value) : data(new int(value)) {}

    // Costruttore di copia (superficiale)
    MyClass(const MyClass& other) : data(other.data) {
        std::cout << "Costruttore di copia superficiale chiamato" << std::endl;
    }

    // Distruttore
    ~MyClass() {
        delete data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        std::cout << "Valore: " << *data << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1; // Costruttore di copia superficiale chiamato
    obj1.print();
    obj2.print();
    return 0;
}

Rule of Five

Esercizio 3: Implementazione della Rule of Five

Creare una classe con costruttore di copia, operatore di assegnazione di copia, costruttore di spostamento, operatore di assegnazione di spostamento e distruttore.
#include <iostream>

class MyClass {
private:
    int* data;
public:
    // Costruttore
    MyClass(int value) : data(new int(value)) {}

    // Costruttore di copia
    MyClass(const MyClass& other) : data(new int(*other.data)) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    // Operatore di assegnazione di copia
    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        *data = *other.data;
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    // Costruttore di spostamento
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    // Operatore di assegnazione di spostamento
    MyClass& operator=(MyClass&& other) noexcept {
        if (this == &other) return *this;
        delete data;
        data = other.data;
        other.data = nullptr;
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    // Distruttore
    ~MyClass() {
        delete data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        if (data)
            std::cout << "Valore: " << *data << std::endl;
        else
            std::cout << "Nessun dato" << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
    obj2.print();
    obj1.print();
    return 0;
}

Esercizio 4: Utilizzo di std::move con la Rule of Five

Creare una classe con la Rule of Five e utilizzare `std::move` per spostare un oggetto.
#include <iostream>
#include <utility> // Per std::move

class MyClass {
private:
    int* data;
public:
    MyClass(int value) : data(new int(value)) {}

    MyClass(const MyClass& other) : data(new int(*other.data)) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        *data = *other.data;
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    MyClass& operator=(MyClass&& other) noexcept {
        if (this == &other) return *this;
        delete data;
        data = other.data;
        other.data = nullptr;
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    ~MyClass() {
        delete data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        if (data)
            std::cout << "Valore: " << *data << std::endl;
        else
            std::cout << "Nessun dato" << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
    obj2.print();
    obj1.print();
    return 0;
}

Esercizio 5: Creazione di un vettore di oggetti con la Rule of Five

Creare una classe con la Rule of Five e utilizzare un vettore per gestire più oggetti.
#include <iostream>
#include <vector>
#include <utility>

class MyClass {
private:
    int* data;
public:
    MyClass(int value) : data(new int(value)) {}

    MyClass(const MyClass& other) : data(new int(*other.data)) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        *data = *other.data;
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    MyClass& operator=(MyClass&& other)

 noexcept {
        if (this == &other) return *this;
        delete data;
        data = other.data;
        other.data = nullptr;
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    ~MyClass() {
        delete data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        if (data)
            std::cout << "Valore: " << *data << std::endl;
        else
            std::cout << "Nessun dato" << std::endl;
    }
};

int main() {
    std::vector<MyClass> vec;
    vec.push_back(MyClass(10));
    vec.push_back(MyClass(20));
    vec.push_back(MyClass(30));

    for (const auto& obj : vec) {
        obj.print();
    }
    return 0;
}

Esercizio 6: Gestione della memoria con la Rule of Five

Creare una classe che gestisce un array dinamico e implementare la Rule of Five.
#include <iostream>
#include <utility> // Per std::move

class MyArray {
private:
    int* data;
    size_t size;
public:
    MyArray(size_t size) : data(new int[size]), size(size) {
        for (size_t i = 0; i < size; ++i) {
            data[i] = static_cast<int>(i);
        }
    }

    MyArray(const MyArray& other) : data(new int[other.size]), size(other.size) {
        std::copy(other.data, other.data + size, data);
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    MyArray& operator=(const MyArray& other) {
        if (this == &other) return *this;
        delete[] data;
        size = other.size;
        data = new int[size];
        std::copy(other.data, other.data + size, data);
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    MyArray(MyArray&& other) noexcept : data(other.data), size(other.size) {
        other.data = nullptr;
        other.size = 0;
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    MyArray& operator=(MyArray&& other) noexcept {
        if (this == &other) return *this;
        delete[] data;
        data = other.data;
        size = other.size;
        other.data = nullptr;
        other.size = 0;
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    ~MyArray() {
        delete[] data;
        std::cout << "Distruttore chiamato" << std::endl;
    }

    void print() const {
        for (size_t i = 0; i < size; ++i) {
            std::cout << data[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    MyArray arr1(10);
    MyArray arr2 = std::move(arr1); // Costruttore di spostamento chiamato
    arr2.print();
    arr1.print(); // Non stampa nulla, arr1 è stato spostato

    return 0;
}

Esercizio 7: Creazione di una classe gestita con std::unique_ptr

Creare una classe che utilizza `std::unique_ptr` per gestire la memoria e implementare la Rule of Five.
#include <iostream>
#include <memory>

class MyClass {
private:
    std::unique_ptr<int> data;
public:
    MyClass(int value) : data(std::make_unique<int>(value)) {}

    MyClass(const MyClass& other) : data(std::make_unique<int>(*other.data)) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        data = std::make_unique<int>(*other.data);
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    MyClass& operator=(MyClass&& other) noexcept {
        if (this == &other) return *this;
        data = std::move(other.data);
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    void print() const {
        if (data)
            std::cout << "Valore: " << *data << std::endl;
        else
            std::cout << "Nessun dato" << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
    obj2.print();
    obj1.print(); // Non stampa nulla, obj1 è stato spostato

    return 0;
}

Esercizio 8: Creazione di una classe gestita con std::shared_ptr

Creare una classe che utilizza `std::shared_ptr` per gestire la memoria e implementare la Rule of Five.
#include <iostream>
#include <memory>

class MyClass {
private:
    std::shared_ptr<int> data;
public:
    MyClass(int value) : data(std::make_shared<int>(value)) {}

    MyClass(const MyClass& other) : data(other.data) {
        std::cout << "Costruttore di copia chiamato" << std::endl;
    }

    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this;
        data = other.data;
        std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
        return *this;
    }

    MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
        std::cout << "Costruttore di spostamento chiamato" << std::endl;
    }

    MyClass& operator=(MyClass&& other) noexcept {
        if (this == &other) return *this;
        data = std::move(other.data);
        std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
        return *this;
    }

    void print() const {
        if (data)
            std::cout << "Valore: " << *data << std::endl;
        else
            std::cout << "Nessun dato" << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
    obj2.print();
    obj1.print(); // Non stampa nulla, obj1 è stato spostato

    return 0;
}