Domanda

Quale comportamento negativo/indefinito potrebbe derivare dal chiamare una funzione di salvataggio (ala boost-serializza) all'interno di una classe ~ dtor?

È stato utile?

Soluzione

Hai due preoccupazioni, una delle quali è una conseguenza dell'altra:

1) Non dovresti consentire alcuna eccezione a sfuggire al distruttore. Se lo fai, e se il distruttore viene chiamato come parte dello stack che si svolge, allora il runtime lo farà terminate() il tuo programma. Questo non è un comportamento indefinito, ma è piuttosto negativo.

Per questo motivo (e ovviamente anche perché i distruttori non restituiscono un valore):

2) Non esiste un modo ragionevole per il tuo distruttore di indicare successo o fallimento (significato "ragionevole", senza costruire una sorta di sistema separato di segnalazione degli errori). Poiché l'utente della tua classe potrebbe voler sapere se il salvataggio è avvenuto o meno, preferibilmente con un'API sensibile per farlo, ciò significa che i distruttori possono salvare i dati solo su una base di "miglior sforzo". Se il salvataggio fallisce, l'oggetto viene ancora distrutto, e quindi presumibilmente i suoi dati vengono persi.

Esiste una strategia per tali situazioni, utilizzata ad esempio dai flussi di file. Funziona così:

  • avere un flush() (o nel tuo caso save()) funzione che salva i dati
  • Chiama questa funzione dal distruttore se l'oggetto non è già stato salvato/arrossato (o più probabile: chiamarla incondizionatamente ma fare in modo che la funzione stessa sappia se deve fare qualsiasi lavoro reale o meno). Nel caso dei flussi di file questo accade tramite close(). Cattura eventuali eccezioni che può lanciare e ignorare eventuali errori.

In questo modo, gli utenti che hanno bisogno di sapere se il salvataggio è riuscito o meno save() per scoprirlo. Agli utenti a cui non importa (o a cui non lo dispiacerebbe avere successo se possibile nel caso in cui un'eccezione venga lanciata e l'oggetto venga distrutto come parte di stack che si svolge) può far provare il distruttore.

Cioè il tuo distruttore Potere Tenta di fare qualcosa che potrebbe fallire, come uno sforzo per ultimo, ma dovresti inoltre fornire un mezzo per gli utenti di fare la stessa cosa "correttamente", in un modo che li informa di successo o fallimento.

E sì, questo significa per inciso che l'uso di flussi senza scaricarli e controllare lo stato del flusso per il fallimento non sta usando loro "correttamente", perché non hai modo di sapere se i dati sono mai stati scritti o meno. Ma ci sono situazioni in cui è abbastanza buono, e negli stessi tipi di situazione potrebbe essere abbastanza buono per la tua classe da salvare nel suo distruttore.

Altri suggerimenti

Il problema è quello boost-serialize può lanciare un'eccezione. Ciò significa che se il distruttore viene chiamato perché un'eccezione si sta propagando e sta ripulendo lo stack mentre si snoda, allora l'applicazione terminerà se il distruttore dell'oggetto lancia un'altra eccezione.

Quindi, per riassumere, vuoi sempre solo un'eccezione che si propaga alla volta. Se finisci con più, allora la tua applicazione si chiuderà il che sconfigge lo scopo delle eccezioni.

È una cattiva idea.

  1. Un distruttore non dovrebbe mai lanciare, È molto probabile che le operazioni IO lanciassero poiché se Io abbia successo o meno è sostanzialmente fuori dal tuo controllo.
  2. Per me almeno è estremamente poco intuitivo
    un. Per uno garantisce che ogni oggetto di quel tipo sarà serializzato (a meno che il distruttore non abbia controlli per impedirlo)
    b. I distruttori hanno uno scopo molto chiaro, per ripulire, memorizzare dati è fondamentalmente l'opposto della pulizia.

Quindi voglio solo fare un altro punto, cosa devi guadagnare serializzando nel distruttore.


Sai che la serializzazione verrà eseguita anche se c'è un'eccezione, se stai utilizzando RAII. Ma questo non è un vantaggio perché anche se il distruttore verrà eseguito, non puoi garantire che la serializzazione verrà eseguita poiché lancia (almeno in questo caso). Inoltre perdi molto della capacità di gestire correttamente un fallimento.

No, non è una cattiva idea, ma non è nemmeno una buona idea! Ma a volte è giusto fare.

Finché proteggi il tuo distruttore dal lanciare eccezioni, non c'è nulla contro di esso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top