Gestione di membri di riferimento con puntatori condivisi [chiuso]

1

È noto che non esiste un meccanismo integrato che impedisca l'invalidazione dei campi membri che fanno riferimento, anche se sono const. (Per ulteriori informazioni sullo sfondo, consultare: link )

La soluzione più semplice è usare solo i campi dei membri non di riferimento, e mi attengo a ciò laddove opportuno.

Tuttavia, per i seguenti motivi, a volte potrebbe non essere una soluzione adeguata:

a) Polymorphism: abbiamo bisogno di riferimenti se non conosciamo il tipo esatto al momento della compilazione.

b) La classe dovrebbe modificare un particolare oggetto, non una copia di esso.

c) La copia può essere costosa.

Ogni volta che un riferimento è inevitabile, suggerisco la seguente regola: lascia sempre che il censore lo prenda per puntatore, non per riferimento. Quindi il chiamante sa meglio cosa aspettarsi.

Per una maggiore flessibilità, ho trovato la seguente idea, che utilizza i puntatori condivisi. Consente all'oggetto di essere passato per riferimento, quindi viene copiato. Inoltre, consente all'oggetto di essere passato dal puntatore condiviso, quindi viene condiviso tra l'oggetto e il chiamante. Il seguente codice lo dimostra. Le classi derivate dalla classe A vengono utilizzate per il campo membro nella classe B . Sono forniti due costruttori per la classe B : uno prende un puntatore condiviso e l'altro prende qualcos'altro e ne fa un puntatore condiviso.

class A {
    public:
    int count = 0;
    virtual void id() = 0;
};
class A1 : public A {
    public:
    void id() {
        ++count;
        std::cout << "A1" << std::endl;
    }
};
class A2 : public A {
    public:
    void id() {
        ++count;
        std::cout << "A2" << std::endl;
    }
};

class B {
    private:
    std::shared_ptr<A> a;
    public:
    template <typename T> B(std::shared_ptr<T> const& arg_a) : a(arg_a) {}
    template <typename T> B(T const& arg_a) : B(std::make_shared<T>(arg_a)) {}
    void operator()() { a->id(); }
};

Possiamo accedere agli oggetti:

auto a1 = A1();
auto a2 = A2();
auto b1 = B(a1);
auto b2 = B(a2);
b1(); std::cout << a1.count << std::endl;
b2(); std::cout << a2.count << std::endl;

Questa stampa:

A1
0
A2
0

Gli 0 sono attesi poiché a1 e a2 sono copiati da make_shared .

Funziona con i temporanei:

auto b1 = B(A1());
auto b2 = B(A2());
b1();
b2();

Qui fingiamo che quando dichiariamo a1 e a2 , non sappiamo ancora quale tipo saranno:

std::shared_ptr<A> a1, a2;
a1 = std::make_shared<A1>(A1());
a2 = std::make_shared<A2>(A2());
auto b1 = B(a1);
auto b2 = B(a2);
b1(); std::cout << a1->count << std::endl;
b2(); std::cout << a2->count << std::endl;

Questa stampa:

A1
1
A2
1

Gli 1 sono attesi dal momento che stiamo condividendo a1 e a2 con gli oggetti della classe B .

Anche il seguente funziona:

auto a1 = std::make_shared<A1>(A1());
auto a2 = std::make_shared<A2>(A2());
auto b1 = B(a1);
auto b2 = B(a2);

Qualche suggerimento o obiezione?

    
posta Lasse Kliemann 16.05.2016 - 17:17
fonte

0 risposte

Leggi altre domande sui tag