possibile ottenere il modello di proprietà di Rust con un wrapper C ++ generico?

13

Esaminare questo articolo sulla sicurezza della concorrenza di Rust:

link

Mi stavo chiedendo quante di queste idee possano essere raggiunte in C ++ 11 (o più recente). In particolare, posso creare una classe proprietaria che trasferisce la proprietà a qualsiasi metodo a cui può essere passata? Sembra che C ++ abbia così tanti modi per passare variabili che sarebbe impossibile, ma forse potrei mettere alcune restrizioni sulla classe o sul modello per garantire che qualche codice template venga eseguito con ogni metodo di passaggio?

    
posta Brannon 10.05.2016 - 18:30
fonte

1 risposta

6

C ++ ha tre modi per passare i parametri a una funzione: in base al valore, al riferimento di lvalue e al riferimento di rvalue. Di questi, il passaggio per valore crea la proprietà nel senso che la funzione chiamata riceve la propria copia, e passando per il riferimento del valore rvalue indica che il valore può essere consumato, cioè non sarà più utilizzato dal chiamante. Il passaggio del riferimento lvalue indica che l'oggetto è temporaneamente preso in prestito dal chiamante.

Tuttavia, questi tendono ad essere "per convenzione" e non possono essere sempre controllati dal compilatore. E puoi accidentalmente trasformare un riferimento di lvalue in un riferimento di rvalue usando std::move() . Concretamente, ci sono tre problemi:

  • Un riferimento può sopravvivere all'oggetto a cui fa riferimento. Il sistema a vita di Rust lo impedisce.

  • Ci possono essere più di un riferimento mutabile / non costante attivo in qualsiasi momento. Il controllore del prestito di Rust lo impedisce.

  • Non puoi disattivare i riferimenti. Non è possibile vedere in un sito di chiamata se tale funzione crea un riferimento al proprio oggetto, senza conoscere la firma della funzione chiamata. Pertanto non è possibile prevenire in modo affidabile i riferimenti, né eliminando alcun metodo speciale delle classi né controllando il sito di chiamata per la conformità con alcune guide di stile "nessun riferimento".

Il problema della durata è relativo alla sicurezza di base della memoria. Ovviamente è illegale utilizzare un riferimento quando l'oggetto di riferimento è scaduto. Ma è molto facile dimenticare la durata in cui si memorizza un riferimento all'interno di un oggetto, in particolare quando quell'oggetto sopravvive all'ambito corrente. Il sistema di tipo C ++ non può tener conto di ciò perché non modella affatto le durate degli oggetti.

Il puntatore smart std::weak_ptr codifica la semantica della proprietà in modo simile a un riferimento semplice, ma richiede che l'oggetto di riferimento sia gestito tramite un shared_ptr , cioè conteggiato con riferimento. Questa non è un'astrazione a costo zero.

Mentre C ++ ha un sistema const, questo non traccia se un oggetto può essere modificato, ma tiene traccia se un oggetto può essere modificato attraverso quel particolare riferimento . Ciò non fornisce garanzie sufficienti per "concorrenza senza paura". Al contrario, Rust garantisce che se esiste un riferimento attivo mutabile che è l'unico riferimento ("Io sono l'unico che può cambiare questo oggetto") e se ci sono riferimenti non modificabili allora tutti i riferimenti all'oggetto non sono mutabili ("Mentre posso leggere dall'oggetto, nessuno può cambiarlo").

In C ++ potresti essere tentato di proteggere l'accesso a un oggetto tramite un puntatore intelligente con un mutex. Ma come discusso sopra, una volta che abbiamo un riferimento, può sfuggire alla sua durata prevista. Pertanto un puntatore così intelligente non può garantire che sia il singolo punto di accesso al suo oggetto gestito. Un simile schema può effettivamente funzionare in pratica perché la maggior parte dei programmatori non vuole sabotare se stessi, ma da un punto di vista del sistema di tipi questo è ancora completamente falso.

Il problema generale con i puntatori intelligenti è che sono librerie in cima al linguaggio principale. L'insieme delle funzionalità del linguaggio principale abilita questi puntatori intelligenti, ad es. std::unique_ptr ha bisogno di costruttori di movimento. Ma non possono correggere le carenze all'interno del linguaggio principale. La capacità di creare riferimenti in modo implicito quando si chiama una funzione e di avere riferimenti ciondolanti insieme significa che il linguaggio C ++ di base non è corretto. L'impossibilità di limitare i riferimenti mutabili a uno solo significa che C ++ non può garantire la sicurezza contro le condizioni di gara con qualsiasi tipo di concorrenza.

Ovviamente sotto molti aspetti C ++ e Rust sono più simili di quanto non siano disali, in particolare per quanto riguarda i loro concetti di vite oggettuali determinate staticamente. Ma mentre possibile è possibile scrivere programmi C ++ corretti (a condizione che nessuno dei programmatori commetta errori), Rust garantisce correttezza riguardo alle proprietà discusse.

    
risposta data 16.11.2017 - 23:39
fonte

Leggi altre domande sui tag