2015-09-25 6 views
5

Sto costruendo un'animazione dinamica & sistema di rendering e vorrei usare Boost.Units per rappresentare le grandezze fisiche per ottenere la bella sicurezza dimensionale. Tuttavia, dovrò passare le matrici di quantitativi attorno a funzioni che non sanno nulla Boost, quali: comandi tampone riempimentoCome digitare-pun Aumentare le matrici di quantità per il tipo sottostante?

  • OpenGL. Questi semplicemente prendono uno const void * e si aspettano di trovare un array di valori float o double durante il dereferenziamento. Leggono i dati.

  • Funzioni di algebra lineare (come gemm o gesv) da diverse implementazioni di BLAS e LAPACK. Questi in genere prendono uno float * o double * in un determinato array. Entrambi leggono e scrivono sui dati.

so che boost::units::quantity<U, T> ha un membro const T& value() che dà accesso diretto riferimento al T valore contenuto. Ho anche verificato che uno boost::units::quantity<U, T> è una struttura di layout standard con esattamente un membro di dati non statici, di tipo T.

Quindi, supponiamo che per un boost::units::quantity<U, T> q, vale quanto segue:

  • static_cast<const void*>(&q) == static_cast<const void*>(&q.value())
  • sizeof(q) == sizeof(T)

La mia domanda è: dato un array boost::units::quantity<U, T> a[100];, è sicuro:

  1. Passa &a[0].value() a una funzione che prevede di leggere un array di 100 oggetti di tipo T all'indirizzo?

  2. Passa reinterpret_cast<T*>(&a[0]) a una funzione che scriverà 100 valori sequenziali di tipo T all'indirizzo?

Sono ben consapevole che questo è probabilmente un comportamento indefinito, ma adesso devo seguire la "praticità batte purezza" (1) principio. Anche se questo è UB, è quello che farà la cosa prevista o morderà in modi imprevisti? Dal momento che questo potrebbe essere specifico per il compilatore: ho bisogno di questo per MSVC moderno (da VS 2015).

E se questo non è sicuro, c'è un modo per farlo in modo sicuro? Con "questo" che si riferisce a "utilizzando Boost.Units con OpenGL e con crunchers di numeri che hanno solo un'interfaccia C," senza copia dei dati inutilmente.


(1) Adattato dal Zen of Python.

+0

Penso dove dici UB vuoi dire IB? Perché nessuno dovrebbe mai scrollarsi di dosso UB. – sehe

risposta

2

Sì, questo sembra qualcosa che puoi fare.

C'è una cosa che non hai menzionato e che dovrebbe essere aggiunta all'elenco delle condizioni da controllare, tuttavia: l'allineamento del tipo di importo spostato deve corrispondere a quello del tipo sottostante. (vedi alignof).

Quindi, in pratica, scriverei codice come questo solo con un numero di static_asserts¹ che proteggono le ipotesi che rendono valida la reinterpretazione.

Se si aggiunge l'asserzione che T è lo stesso di remove_cv_t<decltype(q.value())>, ciò dovrebbe essere affidabile.

Con queste pre-cautele in atto non ci dovrebbe essere UB, solo IB (implementazione definita comportamento) a causa della semantica di reinterpret_cast sulla tua piattaforma particolare.

¹ e forse il debug di asseriscono che &q.value() == &q

+1

Ma la violazione della rigida regola di aliasing è UB, non IB. (È violato nelle funzioni chiamate, cioè il codice BLAS/LAPACK/OpenGL C lo viola). – dyp

+0

Mmm. C'è quell'aspetto. Non so se questo sia necessariamente un problema, ma è certamente un'area da esaminare. – sehe

+0

@dyp Aliasing rigoroso era anche la mia preoccupazione. Allo stesso tempo, ci * è * in realtà un oggetto di tipo 'float' a quell'indirizzo (come un suboggetto dell'oggetto completo di tipo' quantity'). Quindi forse il rigoroso aliasing non viene violato grazie a questo? – Angew

Problemi correlati