2011-01-19 17 views
26

Nello standard C++ 0x in arrivo, cosa succede quando viene lanciata un'eccezione all'interno/durante il costruttore di movimento?C++ Move semantica ed eccezioni

L'oggetto originale rimane? o sono sia l'originale che lo spostamento dell'oggetto in uno stato indefinito? quali sono le garanzie offerte dalla lingua?

+0

Mi chiedo se questo è come il distruttore in cui è solo una cosa negativa se viene generata un'eccezione. Suppongo che nella maggior parte dei casi puoi muoverti senza mai fare nulla che possa lanciare, dato che stai (di solito) semplicemente spostando puntatori in giro ... – templatetypedef

+3

Quindi quello che stai dicendo è che non dovrebbe esserci modo essere lanciato perché lo stato dei membri copiati non viene mai modificato durante l'operazione di spostamento? –

+2

Sorta- è simile all'argomento induttivo che si usa per dimostrare che 'swap' non può essere lanciato. Come caso base, la riassegnazione e la copia delle primitive non vengono mai lanciate. Come una fase induttiva, un costruttore di mosse per un oggetto con alcuni membri di dati può spostare quei membri di dati senza lanciare (ipotesi induttiva!), e quindi può muoversi senza lanciare. Indipendentemente, però, voglio ancora sapere qual è la risposta corretta alla tua domanda. – templatetypedef

risposta

3

Dipende dal tipo di spostamento da. È possibile lanciare esplicitamente un'eccezione, ovviamente, da un agente di movimento, ma anche chiamare implicitamente un copy ctor per un subobject da un agente di movimento. Quella copia può fare qualcosa che può lanciare, come allocare memoria. Quindi, per l'oggetto di origine, la garanzia minima è il valore originale può o non può rimanere, ma dovrebbe essere ancora in uno stato distruttibile.

Per l'oggetto da spostare, equivale a lanciare da un Ctor nel C++ corrente: distruggere qualsiasi base e membro costruiti, eseguire il gestore try della funzione del ctor, se presente, quindi propagare l'eccezione. I dettagli sono in N3225 §15.2p2.

In particolare, si noti che i contenitori richiedono loro tipi allocatore non hanno gettando ctors movimento:

Tale costruzione giocata della allocatore non deve uscire tramite un'eccezione. [N3225 §23.2p8]

Ciò consente ai contenitori di spostare gli allocatori in giro e utilizzare quegli allocatori per ripulire gli elementi in caso di eccezione durante lo spostamento o la copia di elementi.

10

Credo che il comitato degli standard abbia tentato originariamente di fare in modo che i costruttori spostati non avrebbero il permesso di fare eccezioni, ma (almeno fino ad oggi) hanno trovato che cercare di far rispettare ciò aveva troppe insidie.

La proposta N3050, "Consentire a Move Constructors to Throw (Rev 1)", è stata incorporata nella bozza di standard. In sostanza, la proposta aggiunge la possibilità per i costruttori di mosse di lanciare, ma di non consentire le mosse di "lancio" da utilizzare per determinate operazioni in cui erano necessarie solide garanzie di sicurezza (la libreria ricadrà per copiare l'oggetto se una mossa non di lancio non è t disponibile).

Se si contrassegna un costruttore di spostamento come non lancio (noexcept) e viene generata un'eccezione, verrà chiamato std :: terminate().

Potrebbe anche essere la pena di leggere un articolo del blog di David Abrahams che discute i problemi che N3050 intendeva affrontare:

+0

Grazie per l'articolo di David Abrahams :) –

+3

Sì, anch'io ho trovato l'intero sito di blog di Cpp-Next piuttosto interessante su articoli degni di nota! –

2

tuo la domanda quindi equivale a una domanda su Exception Guarantees. Esistono 3 tipi di garanzie sulle eccezioni (applicabili alle funzioni):

  • Nessuna garanzia di eccezione (non proprio un tipo ...
  • Basic Exception Guarantee: tecnicamente corretto, ma non funzionalmente corretto (ovvero nessuna risorsa è trapelata, il programma terminerà senza una brusca interruzione, ma potrebbe essere indesiderato effetti collaterali, come il pagamento incassato, ma il comando non è stato registrato)
  • Strong Exception Guarantee: Tutto o niente (come una transazione), ovvero tutto è fatto correttamente oppure si esegue il rollback al precedente stato.
  • No Throw Exception Guarantee: Questo non genera, mai, quindi nessuna preoccupazione.

Quando si compone la vostra funzione, è di solito prendere funzioni esistenti con le proprie garanzie. È difficile aumentare la garanzia di eccezione, cioè il tuo è generalmente limitato dalla garanzia più debole utilizzata.

W.r.t tua domanda, ci vogliono almeno un eccezione forte garanzia per l'oggetto originale di essere lasciato intatto, se viene generata un'eccezione.

Quindi, cosa succede se un'eccezione viene lanciata durante la costruzione del movimento? Dipende dalle garanzie esposte dagli oggetti secondari e il modo in cui ha unito le chiamate ...

  1. Se viene generata un'eccezione da un costruttore, l'oggetto non è in costruzione e tutti i sotto-oggetti costruiti vengono distrutti, in ordine inverso. Questa regola è applicabile anche a un costruttore di movimenti
  2. A meno che non si "avvolga" il costruttore in un tentativo di cattura e in qualche modo si ripristinino gli oggetti che sono stati spostati, avranno perso le loro risorse. Si noti che devono comunque essere ancora in uno stato distruttibile, quindi tecnicamente il programma sarà corretto.

In termini di eccezioni garanzie, vuol dire che per impostazione predefinita, se tutti i costruttori sottooggetti soddisfare almeno i eccezione di base Garanzia, allora il vostro costruttore mossa troppo, senza alcuna cura speciale.

Tuttavia, anche se i costruttori di tutti i sottooggetti incontrano la garanzia eccezione forte, è improbabile si riuscirà ad avere il proprio costruttore mossa incontrano: questo è lo stesso problema che concatenamento transazioni non produce una transazione.

Se solo uno dei costruttori dei sottoprogetti può lanciare e soddisfa la Strong Exception Guarantee, il costruttore di movimento lo incontrerà naturalmente se si inizializza prima l'oggetto di lancio.

Spero che questo ha aiutato ... eccezioni sono una belva da domare :)