2015-10-16 29 views
8

La mobilità consente una grande classe di ottimizzazioni. Eppure, ci si sente che lo fa a costo di un foro nella sicurezza statica di programmi:C'è un modo per identificare meccanicamente quali operazioni sono sicure su un oggetto spostato da?

Dopo una mossa, l'oggetto di origine viene lasciato in uno stato valido, ma non specificato, dove alcune operazioni sono legali, ma alcuni non lo sono. (In particolare vedere this SO question per le discussioni su questo argomento). Sembrerebbe che questo elenco di operazioni, anche se dipende da ciascun tipo, possa essere conosciuto in fase di compilazione. Tuttavia, il compilatore non mette in guardia circa gli usi non corretti degli oggetti spostati da (come discute lo this other SO question).

Sembrava che la filosofia C++ facesse affidamento sul compilatore per convalidare il più possibile (di ciò che è noto staticamente), uno dei tanti esempi di applicazione della conformità. Tuttavia, sembra che l'oggetto spostato da un oggetto possa essere utilizzato in modi pericolosi, senza che il compilatore possa tentare (o avere alcun mezzo) di catturarli.

Esiste effettivamente un meccanismo che consenta una migliore diagnostica dal compilatore? In caso negativo, perché non esiste un nuovo qualificatore da applicare ai metodi che possono essere utilizzati su un oggetto spostato da un altro o un altro meccanismo che consente verifiche statiche equivalenti?

+0

Tale analisi statica è costosa e aumenterebbe in modo proibitivo i tempi di compilazione. Potresti avere un [linter] (https://en.wikipedia.org/wiki/Lint_%28software%29) separato per controllare invece queste cose. –

+0

@JoachimPileborg: non vedo come uno strumento automatico possa raggiungere questo obiettivo. –

+1

@LightnessRacesinOrbit sicuro, potrebbe cercare attributi che dichiarano i metodi come pericolosi sugli oggetti in uno stato specifico. Tuttavia, penso che non solo non ne valga la pena, ma anche che sia fuorviante, perché i difetti di progettazione dovrebbero essere risolti cambiando il design, non in qualche modo lavorando attorno a loro. – cdonat

risposta

4

La mobilità consente una grande classe di ottimizzazioni. Tuttavia, sembra che lo faccia al costo di dare un buco alla sicurezza statica dei programmi.

Sì, lo fa.

Sembrerebbe che questo elenco di operazioni, anche se dipende da ciascun tipo, possa essere conosciuto in fase di compilazione.

Ma non dal compilatore, in generale.

Tuttavia, il compilatore non avvisa in caso di utilizzo non corretto di oggetti spostati da.

Sarebbe bello, però!

No, dovrai fare affidamento sulla documentazione. O semplicemente fai quello che faccio e, dopo essere stato spostato da un lvalue, non usare mai più quell'oggetto a meno che tu non abbia immediatamente un controllo strettamente controllato e qualche ovvia operazione di "reset" sull'oggetto.

Ovviamente, lo spostamento da un valore non presenta questo problema.

+0

Grazie per l'illuminazione;) Sembra vero che il compilatore non può con l'attuale livello di informazione come (-> la conoscenza di quali operazioni sono definite su mosse-da parte dell'interfaccia informale). Ma questa conoscenza non potrebbe essere resa disponibile al compilatore attraverso un meccanismo standard (ad esempio un nuovo qualificatore sui metodi, come un ipotetico 'moving-safe'). –

+0

@AdN: In teoria, il linguaggio potrebbe essere esteso per aggiungere una funzione del genere? Sì, probabilmente. La caratteristica avrebbe abbastanza valore da giustificare la sua complessità? No, probabilmente no. È probabile che il gruppo di lavoro ISO lo aggiunga alla lingua prima della morte termica dell'universo? Ne dubito!! –

+0

@LightnessRacesinOrbit Direi che una sorta di sistema di caratteri in fase di compilazione (concetti?) Potrebbe risolvere questo problema. – VermillionAzure

0

Ogni volta che uno dei tuoi oggetti, che esistono, si trova in uno stato, che alcune operazioni sono consentite e altre no, probabilmente hai un problema di progettazione. Di solito questo è un forte segnale per la violazione del principio di responsabilità unica. Almeno tutte le funzioni membro dovrebbero avere un comportamento definito in ogni caso - forse genererà un'eccezione.

Così ogni volta che chiedi a quali operazioni sei autorizzato a chiamare su un oggetto in uno stato specifico, ripensa il tuo progetto.

+0

'pop_back' (un'operazione) non è consentito sui vettori vuoti (uno stato specifico di' std :: vector'). Pensi che il comitato dovrebbe ripensare il loro design? –

+0

sì, 'pop_back()' ha un comportamento indefinito su un vettore vuoto. Penso che sia un difetto di progettazione. Non sono a conoscenza di una buona ragione per non definire, che ad es.silenziosamente non fare nulla in quel caso. – cdonat

+0

Il motivo di questa scelta è probabilmente la prestazione di runtime. –

1

Penso che sia improbabile che alcuni standard aggiuntivi verranno aggiunti allo standard per un caso limite come questo.

Una possibilità sarebbe quella di contrassegnare le dichiarazioni di funzione con #pragma supports_moved_from o qualcosa del genere, quindi creare uno strumento di analisi statica per rilevare le chiamate a funzioni su oggetti potenzialmente spostati da e verificare se sono stati contrassegnati.

Probabilmente si potrebbe usare uno dei tanti Clang tool interfaces per questo.

+1

Questo è il più vicino possibile ma, fino a quando le implementazioni della libreria standard lo fanno, non è una soluzione generale. –

0

Esiste effettivamente un meccanismo che consenta una migliore diagnostica dal compilatore?

Non c'è niente di fermare un compilatore di tentare qualche analisi statica di abusi di mosso-da oggetti: ciò equivale a più o meno lo stesso di ri-segna l'oggetto come essere in uno stato Non inizializzato, e molti compilatori Invia avviso per l'uso di variabili che non sono sicure sono state inizializzate.

Detto questo, lo standard normalmente non richiede questo tipo di diagnostica: sono potenzialmente costosi in fase di compilazione, in genere sono imperfetti (ad esempio se si passa un riferimento non-const a un oggetto spostato da una funzione che chiami e l'implementazione non è nell'unità di traduzione (cioè non visibile al compilatore) - non può sapere se l'oggetto spostato da "può essere" utilizzato senza alcun tipo di operazione di assegnazione/ripristino precedente a un significato valore.

Allo stesso modo, se si passa un non- const riferimento a qualsiasi oggetto a qualsiasi funzione la cui definizione non è noto, è possibile non sapere se tale oggetto può essere spostato all'interno della funzione.

In caso negativo, perché non esiste un nuovo qualificatore da applicare ai metodi che possono essere utilizzati su un oggetto spostato da un altro o un altro meccanismo che consente verifiche statiche equivalenti?

La linea di fondo è che ci sono alcune volte è relativamente facile per un compilatore riconoscere che un oggetto è uno stato spostato da, e molte volte quando non può. Un qualificatore potrebbe essere utile, ma senza dubbio sarebbe scambiato per un sacco di persone come garanzia che un oggetto spostato da non può essere abusato, e ci sarebbe un flusso costante di domande e bug correlati. Non avendo una verifica dello sforzo migliore e avendo il programmatore chiaro che è responsabilità dell'analisi di un problema, a volte può essere meglio che dare agli sviluppatori un falso senso di sicurezza.

1

Dato n4034 e std::experimental::optional, si può immaginare un optional con un'operazione di spostamento da vuoto.

Tale oggetto si troverebbe in uno stato "non valido" dopo essere stato spostato.

Avresti ancora bisogno di un qualche modo per esprimere il cambiamento di stato in modo che i compilatori C++ siano in grado di controllarlo staticamente.

In teoria, un'estensione di linguaggio che consente operazioni di mutare il tipo di una variabile durante la sua vita potrebbe essere aggiunta a C++, così come annotazioni di tipo; quindi un valore spostato da potrebbe essere modificato per applicare quell'annotazione e le operazioni che non sono valide per un valore spostato da trigger causerebbero errori del compilatore.

.reset() le operazioni di stile potrebbero essere valide sia su valori spostati da valori non mossi da e riportare le annotazioni su "normale" in entrambi i casi.

Non sono esperto, ma credo che Rust tenti di fare qualcosa del genere per risolvere problemi simili; il programmatore deve dimostrare al sistema di tipi che determinate operazioni sono valide.

Questo è anche simile a recent work in caso di rilevamento statico del puntatore di perdite/invalidi.