2012-12-13 25 views
98

Se ho una variabile all'interno di una funzione (ad esempio un array di grandi dimensioni), ha senso dichiararla sia static e constexpr? constexpr garantisce che l'array sia stato creato in fase di compilazione, quindi lo static sarebbe inutile?La variabile statica constexpr ha senso?

void f() { 
    static constexpr int x [] = { 
     // a few thousand elements 
    }; 
    // do something with the array 
} 

È il static effettivamente facendo qualcosa là in termini di codice o la semantica generato?

+11

'constexpr' non garantisce nulla in fase di compilazione, il compilatore è libero di valutare le cose' constexpr' in fase di runtime. È solo costretto a valutare qualcosa in fase di compilazione se si utilizza quel qualcosa in contesti in cui è necessario essere conosciuto in fase di compilazione. – Praetorian

+0

Credo che @Praetorian sia corretto, e 'static' garantirà non solo che è in fase di compilazione, ma che è memorizzato solo con le costanti di tempo di compilazione. Penso che senza 'static' sarebbe _ teoricamente_ conforme a spingere la matrice (enorme) sullo stack ad ogni invocazione della funzione. –

+3

@AndrewLazarus, non solo è teoricamente conforme per spingere la matrice nello stack ad ogni invocazione, è teoricamente richiesto (modulo la regola as-if). In pratica, nella mia esperienza, succede sempre molto bene. Vedi la mia risposta per maggiori dettagli. – rici

risposta

120

La risposta breve è che non solo è static utile, è abbastanza bene sarà sempre desiderato.

Innanzitutto, notare che static e constexpr sono completamente indipendenti l'uno dall'altro. static definisce la durata dell'oggetto durante l'esecuzione; constexpr specifica che l'oggetto deve essere disponibile durante la compilazione. La compilazione e l'esecuzione sono disgiunte e discontinue, sia nel tempo che nello spazio. Quindi, una volta che il programma è stato compilato, constexpr non è più rilevante.

Ogni variabile dichiarata constexpr è implicitamente const ma const e static sono quasi ortogonali (tranne che per l'interazione con static const numeri interi.)

Il modello C++ oggetti (§ 1.9) richiede che tutti gli oggetti diversi bit-field occupano almeno un byte di memoria e indirizzi; inoltre tutti questi oggetti osservabili in un programma in un dato momento devono avere indirizzi distinti (paragrafo 6). Questo non richiede al compilatore di creare una nuova matrice sullo stack per ogni richiamo di una funzione con un array const non statico locale, in quanto il compilatore potrebbe trovare rifugio nel principio as-if a condizione che provi che nessun altro oggetto di questo tipo può essere osservato

Questo non sarà facile da provare, sfortunatamente, a meno che la funzione non sia banale (ad esempio, non chiama nessuna altra funzione il cui corpo non è visibile all'interno dell'unità di traduzione) perché gli array, più o meno per definizione, sono indirizzi. Pertanto, nella maggior parte dei casi, la matrice non statica const(expr) dovrà essere ricreata nello stack ad ogni richiamo, il che vanifica il punto di essere in grado di calcolarlo in fase di compilazione.

D'altra parte, un oggetto locale static const è condiviso da tutti gli osservatori e inoltre può essere inizializzato anche se la funzione in cui è definita non viene mai chiamata. Quindi, nessuno dei precedenti si applica e un compilatore è libero non solo di generare solo una singola istanza di esso; è libero di generare una singola istanza in memoria di sola lettura.

Quindi dovresti usare sicuramente static constexpr nel tuo esempio.

Tuttavia, vi è un caso in cui non si desidera utilizzare static constexper. A meno che un oggetto dichiarato constexpr sia ODR-usato o dichiarato static, il compilatore è libero di non includerlo affatto. È piuttosto utile, perché consente l'utilizzo di array temporanei constexpr temporanei senza eseguire il polling del programma compilato con byte non necessari. In tal caso, chiaramente non si desidera utilizzare static, poiché è probabile che lo static imponga l'esistenza dell'oggetto in fase di esecuzione.

+1

Stavo pensando a questo quando ho fatto il commento. ISTM 'constexpr', a differenza di' const', può sempre essere messo in una memoria di sola lettura (non è possibile gettare via 'constexpr' [?]) E ciò eviterebbe la necessità di spingere una nuova copia nello stack, anche quando sarebbe richiesto per le variabili 'const'. Un po 'come un pool di stringhe letterali costanti. Ma non so se sia legale. –

+1

@AndrewLazarus, non puoi lanciare 'const' da un oggetto' const', solo da un 'const X *' che punta a un 'X'. Ma non è questo il punto; il punto è che gli oggetti automatici non possono avere indirizzi statici. Come ho detto, 'constexpr' cessa di essere significativo una volta che la compilazione è terminata, quindi non c'è nulla da gettare via (e molto probabilmente nulla, perché l'oggetto non è nemmeno garantito di esistere in fase di esecuzione.) – rici

+0

In C++ 1y, le funzioni di contexpr NON saranno const. – refi64

Problemi correlati