Zamiana raw pointer na unique_ptr

0

Cześć, mam taki problem potrzebuję zamienić w ponieższym kodzie zwykłe wskaźniki na unique_ptr. W int main() zamieniłem już zwykłe wskaźniki ale nie wiem jak to zrobić w reszcie kodu (w klasach). Cały kod nie jest mój, ja jedynie mam wykonać zamianę. Mógłby ktoś wyjaśnić jak to zrobić ?

#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <algorithm>
#include <random>
#include <memory>
using namespace std;

class Obserwator {
    public:
        Obserwator(const char* s) : nazwa{s ? s : "nienazwany"} { /* nic nie robi */ }
        virtual ~Obserwator() { } // klasa bazowa
        const char* id() const { return nazwa.c_str(); }
        virtual void update() = 0; // metoda czysto wirtualna
    private:
        string nazwa;
};

class Manager {
    public:
        void dodaj(Obserwator* p);
        void usun(Obserwator* p);
        void powiadom();
        void obserwatorzy() const;
    private:
        list<Obserwator*> klient;
};

void Manager::obserwatorzy() const {
    if (klient.empty()) cout << "Brak obserwatorow\n";
    auto it = klient.cbegin();
    while(it != klient.cend()) {
        cout << "Obserwator " << (*it)->id() << endl;
        ++it;
    }
}

void Manager::powiadom() {
    for (auto& p : klient) p->update();
}

void Manager::dodaj(Obserwator* p) {
    if (find(begin(klient),end(klient),p) == end(klient)) {
        klient.push_back(p);
    } else {
        cout << "Obserwator " << p->id() << " jest juz na liscie\n";
    }
}

void Manager::usun(Obserwator* p) {
    klient.erase(find(begin(klient),end(klient),p));
}

class Meteo : public Manager {
    public:
        double getT() const { return t; }
        void operator()(size_t n);
    private:
        double t {0.};
        double a {5.};
        double b {25.};
        double losuj(double a, double b);
        random_device rd;
        mt19937 gen { rd() };
        uniform_real_distribution<> dis { a, b };
};

double Meteo::losuj(double a, double b) {
    return dis(gen);
}

void Meteo::operator()(size_t n) {
    while (n--) {
        t = losuj(a,b);
        powiadom();
    }
}

class Monitor : public Obserwator {
    public:
        Monitor(const char* s, const Meteo& r) : Obserwator(s), ref(r) { }
        void update() override {
            t = ref.getT();
            cout << "Obserwator " << id() << " t = " << t << endl;
        }
    private:
        double t {0.};
        const Meteo& ref;
};

class MonitorSredni : public Obserwator {
    public:
        MonitorSredni(const char* s, const Meteo& r)  : Obserwator(s), ref(r) { }
        void update() {
            vec.push_back(ref.getT());
            tsr = 0.;
            for (const auto& d : vec) tsr += d;
            tsr /= vec.size();
            cout << "Obserwator " << id() << " t srednia = " << tsr << endl;
        }

    private:
        double tsr {0.};
        vector<double> vec;
        const Meteo& ref;
};

int main() {
    Meteo stacja;

    unique_ptr<Obserwator> p1(new Monitor("Monitor 1",stacja));
    unique_ptr<Obserwator> p2(new Monitor("Monitor 2",stacja));
    unique_ptr<Obserwator> p3(new Monitor("Monitor 3",stacja));
    unique_ptr<Obserwator> p4(new Monitor("Monitor 4",stacja));


    stacja.obserwatorzy(); // pusta lista
    stacja.dodaj(p1);
    stacja.dodaj(p2);
    stacja.dodaj(p3);
    stacja.dodaj(p4);
    stacja.obserwatorzy(); // lista nazw wszystkich podłączonych obserwatorów
    stacja(2); // dwa losowania, stacja.operator()(2);
    stacja.dodaj(p1); // sprawdzenie, czy p1 jest już na liście
    stacja.usun(p3); // od teraz p3 nie jest obserwatorem
    stacja(3);

}
1

raczej to powinny być shared_ptr bo tu używasz więcej niż raz p1 czy p3. zawsze oczywiście można robić refrence do unique_ptr(link) ale niekoniecznie to tu pasuje.

1

Najlepszy materiał, wyjaśniający kiedy ma być shared_ptr unique_ptr weak_ptr czy może surowy wskaźnik:

Teraz twój kod trzyma pX w main i przekazuje do stacja.
Ergo twoje wskaźniki unique_ptr nie są unikalne.
Teoretycznie można to zostawić w takim stanie, że main jest właścicielem pX (okropna nazwa symbolów), a następnie przekazać surowy wskaźnik do reszty kodu. Jest to jak najbardziej ok, dopóki kod zapewnia, że czas, życia pX jest dłuższy niż czas życia stacja.

Jeśli chcesz "przenosić" (std::move) pX do stacaja, to jest też dobre podejście, pytanie tylko jak wtedy obsłużyć funkcjonalność usuwania (Manager::usun)? Obecnie usuwasz przez przekazanie tego samego wskaźnika do stacja, ale w tym przypadku main oddał tę informację do stacja i już jej nie posiada (w końcu wskaźnik unikalny).

1 użytkowników online, w tym zalogowanych: 0, gości: 1