Se una classe che ha un metodo per creare l'oggetto A implementa anche un metodo per eliminare A?

0

Ad esempio, supponiamo di avere una classe per creare un pulsante con stili specifici comuni alla mia app:

class ButtonFactory{
public:
  static Button* createAppButton(std::string st,int font size){
    Button* b=new Button();
    //b->setColor();b->setText()...;b->playAnimation(...);
    return b;
  }
}

in un'altra classe

this->b=ButtonFactory::createAppButton("OK",20);
.
.
.
//delete it at destructor
delete b;

Tuttavia, mi sento a disagio che "nuovo" e "cancella" non siano della stessa classe. Quindi la mia domanda è, dovrei anche creare un metodo di eliminazione in ButtonFactory:

static void deleteAppButton(Button* b){
  delete b;
}
.
.
.
ButtonFactory::deleteAppButton(this->b);

invece di eliminare b per parole chiave direttamente?

    
posta mmmaaa 25.07.2018 - 04:44
fonte

4 risposte

4
  • Con la gestione manuale delle risorse, questo è un must. Sicuramente vuoi fornire un metodo distruttore. C è una buona illustrazione per questo, letteralmente ogni allocatore ha un distruttore di accompagnamento.
  • Con memoria gestita Il pulsante dovrebbe implementare l'interfaccia monouso, che gestisce la distruzione (compilazione assistita). Java e C # sono famosi per le loro perdite di risorse causate dall'abuso di Monouso.
  • C ++ e Rust (RAII resource management) suggeriscono di restituire un oggetto che ne gestisce la durata. RAII trasferisce la responsabilità della gestione delle risorse da un nuovo proprietario all'assegnazione del codice, separando la proprietà e i problemi di gestione delle risorse.

In questo caso, probabilmente un metodo restituirà unique_ptr<Button> . Il puntatore intelligente potrebbe includere un distruttore personalizzato, se di default uno non è adatto in futuro.

Altri approcci possono essere giustificati, ma non c'è nulla che indichi questo nel tuo esempio. Per favore, spiega, perché usi i puntatori grezzi?

    
risposta data 25.07.2018 - 06:08
fonte
0

L'oggetto della classe dovrebbe essere in grado di prendersi cura della propria pulizia. Questa è una buona pratica.

Se segui il tuo approccio con ButtonFactory::deleteAppButton(this->b) , allora il codice chiamante deve sapere che l'oggetto della classe Button deve essere smaltito in un modo speciale. Ciò aumenta il rischio che qualcuno si dimentichi di chiamare ButtonFactory::deleteAppButton(...) .

Inoltre ...

Immagina una classe Button che non può occuparsi di fare tutta la distruzione da sola e ha bisogno di assistenza da un'altra classe. Ad esempio, alcune risorse per gli oggetti Button provengono da un pool e devono tornare al pool.La gestione del pool viene eseguita da una classe separata. Quindi la classe Button deve chiamare l'oggetto del gestore di pool nel distruttore. Per essere in grado di farlo, la classe Button dovrebbe mantenere un puntatore all'oggetto del gestore di pool. Il codice chiamante dovrebbe fare solo delete b .

    
risposta data 25.07.2018 - 05:38
fonte
0

Questo è molto dipendente dalla lingua.

Che cosa stai scrivendo è un buon vecchio wizdom di codifica in C. Perché

  • C non ha alcun metodo standard di pulizia
  • C viene utilizzato per produrre librerie condivise altamente portatili e talvolta non esiste letteralmente il codice "runtime" condiviso da una libreria che si utilizza e il resto dell'applicazione

Quindi è consuetudine che C ogni API abbia le proprie funzioni di pulizia per i propri tipi, come curl_multi_cleanup ()

Per la situazione in C ++ è un po 'diverso. Esiste un modo standard per eliminare gli oggetti, inoltre, di solito non li elimini in modo esplicito, ma usa RAII e distruttori per farlo. Quindi per C ++ idiomatico dovresti rendere l'oggetto cancellabile con semplice delete . Inoltre, i requisiti di portabilità per il codice C ++ sono molto meno rigidi: di solito ti aspetti che una libreria che usi e codice che la usa sia compilata con lo stesso compilatore, la libreria standard e altre dipendenze.

    
risposta data 25.07.2018 - 06:02
fonte
0

Lo SCOPO di una fabbrica è di astrarre le scelte su come creare una particolare istanza. Questo in genere significa, selezionando quali informazioni extra si devono applicare e sottotipo. Se implica una gestione speciale dell'eliminazione dell'oggetto, dovrebbe generalmente essere iniettato nello smartpointer stesso (in deleter C ++ o Button o distruttore sottoclasse).

Le fabbriche NON hanno NIENTE a che fare con la durata dell'oggetto.

Come altri hanno menzionato, la gestione della vita dell'oggetto dipende in qualche modo dalla lingua. Dato che sembra che tu stia usando C ++ (e dal momento che IMHO ha il miglior / più potere su questo aspetto della programmazione), ti sarebbe utile prendere in considerazione l'utilizzo di puntatori intelligenti per gestire la durata dei tuoi oggetti.

Ad esempio, vorrei usare:

class ButtonFactory{
public:
  static shared_ptr<Button> createAppButton(std::string st,int font size){
    shared_ptr<Button>  = make_shared<Button> ();
    //b->setColor();b->setText()...;b->playAnimation(...);
    return b;
  }
}

Nota: quando si esegue questa operazione, è importante memorizzare una copia esplicita del puntatore intelligente in qualche luogo, poiché quando l'ultimo riferimento al puntatore intelligente scompare, l'oggetto verrà eliminato.

    
risposta data 25.07.2018 - 15:33
fonte