Discussione:
Dubbio dichiarazione unique_ptr
(troppo vecchio per rispondere)
Emanuele Merlo
2017-12-12 09:07:38 UTC
Permalink
Mi trovo in un caso reale che posso semplificare così:


Pippo
{
/* ... vari costruttori e metodi */

Pippo* Clona() { return new Pippo(*this); }
}


void Funzione(Pippo* p1)
{
auto p1_ptr = std::make_unique<Pippo>(p1->Clona()); // dichiarazione #1

/* oppure */

auto p1_ptr = std::make_unique<Pippo*>(p1->Clona()); // dichiarazione #2
}


Qual è la dichiarazione corretta?
Emanuele Merlo
2017-12-12 09:16:18 UTC
Permalink
Post by Emanuele Merlo
Qual è la dichiarazione corretta?
e se fosse:

auto p1_ptr = std::make_unique</*?*/>(new Pippo());

?
enoquick
2017-12-13 03:35:50 UTC
Permalink
Post by Emanuele Merlo
Pippo
{
/* ... vari costruttori e metodi */
Pippo* Clona() { return new Pippo(*this); }
}
void Funzione(Pippo* p1)
{
auto p1_ptr = std::make_unique<Pippo>(p1->Clona()); // dichiarazione #1
/* oppure */
auto p1_ptr = std::make_unique<Pippo*>(p1->Clona()); // dichiarazione #2
}
Qual è la dichiarazione corretta?
Nessuna delle due



class pippo {
public:
using unique_pointer_type=std::unique_ptr<pippo>;
unique_pointer_type clone()const { return unique_pointer_t(new
pippo(*this);}
private:
pippo(const pippo&) ....
};

quest perche la funzione clone e' costante e deve dare come risultato un
unique pointer in modo che l'ulizzatore della classe non debba
ricordarsi di usare delete

Mai fare fuoriuscire un pointer nudo e crudo che l'utilizzatore deve
liberare con delete
E' una pessima progettazione.

Altra cosa,il metodo clone in questo caso non serve a molto (basta un
normale copy constructor)
Di solito e' utile se si usa l'ereditarieta' in modo da avere un copy
constructor virtuale (ed eventualmente anche un costruttore virtuale)


class base {
public:
using unique_pointer_type=std::unique_ptr<base>;
static unique_pointer_type make_instance(); //costruisce una classe
derivata da base in base ad alcune condizioni
virtual unique_pointer_type clone()const ...
protected:
base() ...
base(const base&) ..
};

class der : public base {
public:
unique_pointer_type clone()const override { return
unique_pointer_type(new der(*this);}
protected:
der(const der&) ...
private:
der() ...
friend unique_pointer_type base::make_instance();
};


class der1 : public base ...

class der2 : public base ...
Emanuele Merlo
2017-12-13 08:39:07 UTC
Permalink
Post by enoquick
quest perche la funzione clone e' costante e deve dare come risultato un
unique pointer in modo che l'ulizzatore della classe non debba
ricordarsi di usare delete
Non ho giurisdizione sulla classe che implementa il "Clona", è un tipo variant personalizzato che arriva da una libreria ed è purtroppo implementato nel modo che ho descritto.
Io sto cercando di rendere la gestione di quel puntatore un minimo più sicura, perché è fonte di memory leaks.
Post by enoquick
Mai fare fuoriuscire un pointer nudo e crudo che l'utilizzatore deve
liberare con delete
E' una pessima progettazione.
Sono d'accordo.
Post by enoquick
Altra cosa,il metodo clone in questo caso non serve a molto (basta un
normale copy constructor)
Di solito e' utile se si usa l'ereditarieta' in modo da avere un copy
constructor virtuale (ed eventualmente anche un costruttore virtuale)
Non so perché sia stata fatta questa scelta. L'implementazione reale è una famiglia di classi che ereditano da un'interfaccia base e implementano una trentina di tipi diversi. Ci sarà qualche motivo architetturale (che non arrivo a comprendere) o un'eredità del passato.

Grazie per la risposta.

f***@gmail.com
2017-12-13 04:09:50 UTC
Permalink
<snip>
Qual è la dichiarazione corretta?
A me pare un po' convoluto...
- perché non chiamare il semplice costruttore di copia?
- se vuoi un puntatore unico, perché non fare un singleton?

Ciao!
Loading...