🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Esercizi Singleton Pattern C++

Codegrind Team•Jul 12 2024

Ecco degli esercizi con soluzione per praticare l’utilizzo del Singleton Pattern in C++.

Esercizio 1: Implementazione base del Singleton Pattern

Creare una classe Singleton con un metodo statico per ottenere l'istanza unica.
#include <iostream>

class Singleton {
private:
    static Singleton* instance;
    Singleton() {}

public:
    static Singleton* getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}

Esercizio 2: Singleton con mutex per thread safety

Modificare la classe Singleton per renderla thread-safe usando `std::mutex`.
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}

public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}

Esercizio 3: Singleton con blocco a doppio controllo

Implementare la classe Singleton usando il blocco a doppio controllo per migliorare l'efficienza del thread safety.
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}

public:
    static Singleton* getInstance() {
        if (!instance) {
            std::lock_guard<std::mutex> lock(mtx);
            if (!instance) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}

Esercizio 4: Singleton con distruzione controllata

Implementare la classe Singleton con un distruttore controllato per gestire correttamente la distruzione dell'istanza.
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}
    ~Singleton() {
        std::cout << "Distruttore Singleton chiamato" << std::endl;
    }

public:
    static Singleton* getInstance() {
        if (!instance) {
            std::lock_guard<std::mutex> lock(mtx);
            if (!instance) {
                instance = new Singleton();
                std::atexit(destroyInstance);
            }
        }
        return instance;
    }

    static void destroyInstance() {
        delete instance;
        instance = nullptr;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}

Esercizio 5: Singleton utilizzando std::call_once

Implementare la classe Singleton utilizzando `std::call_once` per garantire l'inizializzazione sicura in ambienti multi-thread.
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::once_flag initFlag;
    Singleton() {}

public:
    static Singleton* getInstance() {
        std::call_once(initFlag, []() {
            instance = new Singleton();
        });
        return instance;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::initFlag;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}

Esercizio 6: Singleton con smart pointer

Implementare la classe Singleton utilizzando `std::shared_ptr` per la gestione automatica della memoria.
#include <iostream>
#include <memory>
#include <mutex>

class Singleton {
private:
    static std::shared_ptr<Singleton> instance;
    static std::mutex mtx;
    Singleton() {}

public:
    static std::shared_ptr<Singleton> getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (!instance) {
            instance = std::shared_ptr<Singleton>(new Singleton());
        }
        return instance;
    }

    void printMessage() {
        std::cout << "Istanza Singleton" << std::endl;
    }
};

std::shared_ptr<Singleton> Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    std::shared_ptr<Singleton> s1 = Singleton::getInstance();
    std::shared_ptr<Singleton> s2 = Singleton::getInstance();

    s1->printMessage();

    std::cout << "s1 e s2 sono uguali: " << (s1 == s2) << std::endl; // Devono essere uguali

    return 0;
}