2013-08-14 8 views
8

Utilizzando C++ 11, mi piace creare un array di booleani e subito chiaro chePosso dire la dimensione di una matrice creata con "nuovo tipo [n]" in C++?

bool *mymap = new bool[n]; 

n è variabile.

Ora, questo cancella già la memoria occupata dall'array? In caso contrario, esiste un approccio migliore per cancellare la matrice rispetto all'utilizzo di un ciclo su tutti gli elementi, impostando ciascuno su false individualmente?

Ho considerato l'utilizzo di std: memset(), ma ciò richiede che conosca la dimensione dell'array. Ora, i principianti potrebbero dire: Facile, la dimensione è n * sizeof (bool). Ma non lo compro. Il compilatore potrebbe decidere di comprimerli in modo diverso, persino impacchettarli come bit, no?

Quindi, c'è un modo per dire la dimensione della matrice in modo più pulito? Immagino che potrebbe esserci una funzione std: arraysize() che restituisce semplicemente lo spazio della matrice allocata in memoria. Dopotutto, tali informazioni devono essere mantenute in fase di esecuzione in qualche modo, o una chiamata di eliminazione non saprebbe quanto rilasci, giusto?

+7

Cosa c'è di sbagliato con 'std :: VECTOR'? – chris

+0

@chris std :: vector overkill nel mio caso d'uso particolare - anche l'uso di un array diretto è più veloce. –

+9

Se si crea un 'std :: vector' con una dimensione specifica, il sovraccarico è minimo. Dovresti davvero confrontarlo. –

risposta

10

La risposta alla domanda specifica è no, non è possibile determinare la lunghezza dell'array puntata da mymap. Il linguaggio semplicemente non fornisce alcun meccanismo per questo.

Ma se tutto quello che vogliamo fare è assicurarsi che tutti gli elementi dell'array sono impostate per false, allora tutto ciò che dovete fare è il valore inizializzarlo:

bool* mymap = new bool[n](); 
//      ^^ 

Purtroppo, questo funziona solo per valori simili a zero per i tipi integrati. Non ci sarebbe alcun modo equivalente per impostare tutti i valori su true.

+2

Oppure puoi usare un'inizializzazione uniforme: 'new bool [n] {}', 'new bool [n] {true, false, true}', etc – bames53

4

No, non è possibile, perché in realtà non è un array. mymap è solo un normale puntatore a una memoria heap e, se è necessario conoscere le dimensioni, è necessario tenerne traccia personalmente o utilizzare un contenitore standard come std::vector.

Oh, e se si desidera una variante più generica di memset leggere su std::fill.

+0

Ti rendi conto che il la funzione malloc conosce la dimensione del blocco alloc'd, giusto? Allora perché non dovrebbe farlo anche il nuovo operatore? –

+0

@ThomasTempelmann 'malloc' e' new' non hanno bisogno di conoscere la dimensione del blocco assegnato - ad esempio, potrebbero arrotondare la dimensione alla successiva potenza disponibile di due (o alla dimensione del prossimo blocco disponibile di uguale o di dimensioni maggiori) e memorizzarlo. Solo il 'nuovo T [n]' dove 'T' è un tipo non POD è necessario per memorizzare l'esatto' n'. – user4815162342

+0

@ThomasTempelmann Il * sistema operativo * può tenere traccia delle dimensioni, ma il compilatore sicuramente non lo fa. Richiede solo il sistema operativo per un pezzo di memoria e poi dimentica la dimensione. –

4

No, il compilatore non può decidere per il confezionamento di loro, tranne in modo che la dimensione della regione è n * sizeof(bool) - fare in nessun altro modo si romperebbe la capacità di affrontare i singoli membri dell'array come mymap[x] (che è lo stesso di *(mymap + x)) .

In questo caso, il suggerimento per principianti è corretto.

6

Non è possibile farlo in un modo standard. Tuttavia, diversi compilatori supportano diversi hack per farlo, ad esempio:

#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32)) 
     // a dirty MSVC and MinGW hack 
     size_t Size = _msize(mymap); 
#elif defined(__GNUC__) 
     // a dirty glibc hack 
     size_t Size = malloc_usable_size(mymap); 
#else 
    #error Implement for any other compiler 
#endif  

Ma questi sono veri hack, quindi attenzione.

A proposito, std::vector può aiutarti a risolvere il tuo problema all'interno dello standard.

2

Si può provare questo:

bool *mymap = new bool[n](); 

Tuttavia questa imposta per false e non è possibile utilizzare un modo per impostare per true.

2

Supponiamo che il compilatore decida di imballare in modo diverso.

Assunzione 1: il compilatore racchiude alcuni bit in un byte. Se si prende l'indirizzo di un singolo elemento all'interno dell'array, è di tipo bool. Dato che il compilatore non può (in generale) dedurre cosa farai con questo indirizzo (ad esempio passandolo ad una funzione che lo passa ad una lib, ...), il bit-packing all'interno di un byte non può realmente accadere. Altrimenti il ​​compilatore deve mascherare il bit appropriato dalla sua area compressa e spostarlo da qualche parte come un vero bool.

Assunzione 2: il compilatore utilizza più del sizeof (bool) per un valore di bool. Altamente improbabile - perché quindi sizeof (bool) sarebbe semplicemente maggiore. Le manipolazioni di puntatori sono ancora possibili e in caso di array di bit è necessario implementare qualche altra logica magica.

Assunzione 3: il compilatore utilizza dimensioni diverse per i diversi campi dell'array - ancora più improbabile. Le informazioni amministrative richieste sono troppo grandi.

Da questi 3 pensieri direi che la soluzione semplice è la migliore. Per sicurezza, per ora e per tutto il futuro del tuo programma, scrivi un piccolo test unitario che verifichi esattamente quello (es. Prendi l'indirizzo del primo valore, gettalo su un puntatore di un tipo che ha lo stesso sizeof di bool, calcola l'indirizzo dell'elemento n, converti quell'indirizzo in un puntatore di bool, scrivi qualcosa lì e confronta con l'accesso dell'array). Quindi riceverai una notifica se qualcosa cambia, ma dubito che lo farà.


Sidenote: ovviamente il compilatore è sempre in grado di allocare più memoria del necessario. Ma ancora, la matrice ha quella dimensione (è appena posizionata in un pezzo più grande di memoria).

+0

Il mio pensiero è questo: mentre un bool potrebbe occupare 1 byte, un array potrebbe utilizzare i limiti di parola per ciascun elemento al fine di ottimizzare le prestazioni di accesso alla memoria. Ma poi, * a è uguale a a [0], e ++ a deve passare all'elemento di array successivo. Con ciò, probabilmente non è permesso al compilatore di comprimere gli elementi dell'array con dimensioni diverse da sizeof (elem). –

+0

se utilizza i limiti delle parole per ottimizzare le prestazioni di accesso, farebbe lo stesso per i singoli valori (si immagini ad esempio nelle strutture). Ciò significa che sizeof (bool) sarebbe 2 e l'ipotesi n * sizeof (bool) == dimensione dell'array si manterrà –

2

Nell'osso C++, no, non è possibile. Comunque sei incoraggiato (e dovresti davvero) a prendere in considerazione l'uso di una classe per gestire comunque la memoria.

in C++ 98, è possibile utilizzare un boost::scoped_array o un std::vector (anche se per bool si potrebbe preferire un std::vector<char>).

in C++ 11, è consigliabile sostituire boost::scoped_array da std::unique_ptr<bool[]>.

Il problema è fino ad allora, a parte std::vector, nessuno di quelli conosce la dimensione della matrice che contengono; gestiscono solo la memoria.

In C++ 14 appare un nuovo contendente: std::dynarray. È una versione ridotta di std::vector la cui dimensione non può essere ridimensionata in modo dinamico. In breve, esattamente quello che vuoi: solo la matrice e la sua lunghezza, senza sovraccarico.

Se il compilatore/toolchain preferito non supporta dynarray ancora si può facilmente implementare da soli:

template <typename T> 
class dynarray { 
public: 
    // methods go here. 
private: 
    size_t size; 
    std::unique_ptr<T[]> array; 
}; // class dyn_array 
+0

Grazie per il puntatore a std: dynarray. Il 2014 non è poi così lontano :) –

Problemi correlati