Capitolo 13. Classi di Strutture di Dati



Scaricare 208 Kb.
Pagina1/5
21.12.2017
Dimensione del file208 Kb.
  1   2   3   4   5

Capitolo 13. Classi di Strutture di Dati


Memorizzare ed elaborare dati è una parte essenziale di qualsiasi applicazione. Dalla classe più semplice per conservare informazioni sulla dimensione e la posizione a tipi complessi come array e mappe hash, le wxWidgets forniscono un’ampia selezione di srutture dati. Questo capitolo presenta molte strutture dati delle wxWidgets, evidenziandone per ciascuna di esse i metodi usati più frequentemente. Le strutture usate con minor frequenza e le funzionalità si possono trovare leggendo la documentazione completa delle API di wxWidgets.

Da notare che in questo libro non si discute delle teorie e delle implementazioni di tali strutture dati. Tuttavia, chiunque dotrebbe essere in grado di usare le classi delle strutture dati, anche senza conoscerne l’interno.


Perché non le STL?


Prima di tutto, occopiamoci di una domanda posta spesso sulle classi di strutture dati delle wxWidgets: "Perché le wxWidgets non usano semplicemente la Standard Template Library (STL)?" La ragione principale è storica: le wxWidgets esistono dal 1992, molto prima che le STL si potessero usare con sicurezza tra varie piattaforme e compilatori. Con l’evoluzione delle wxWidgets, molte delle classi delle strutture hanno gravitato attorno ad API simili alle STL, e ci si aspetta che eventualmente quelle equivalenti STL sostituiranno le classi wxWidgets.

Nel frattempo, si possono usare le funzionalità STL nelle applicazioni wxWidgets impostando wxUSE_STL a 1 in setup.h (o passando enable-stl nella configurazione) per basare le wxString ed altri contenitori [containers] sulle equivalenti STL. Si avverte che l’uso delle STL con le wxWidgets può incrementare sia la dimensione della libreria che il tempo di compilazione, specie se si usa GCC.


Stringhe


I benefici di lavorare con una classe stringa anziché i puntatori a carattere standard sono ben noti. Le wxWidgets includono la propria classe stringa, wxString, usata sia internamente che per passare e restituire informazioni. wxString possiede tutte le operazioni standard che ci si aspetta di trovare in una classe stringa: gestione dinamica della memoria, costruzione da altre stringhe, stringhe e caratteri C, operatori di assegnazione, accesso ai singoli caratteri, concatenazione e confronto, estrazione di sottostringhe, conversione di maiuscole/minuscole, troncamento e riempimento (con spazi), ricerca e sostituzione, printf, come in C, funzione di inserimento tipo stream, ed altro ancora.

Oltre ad essere un’ulteriore classe stringa, wxString ha altre utili funzionalità. wxString supporta pienamente Unicode, includendo i metodi per convertire in e da ANSI e Unicode a prescindere dalla configurazione della build. L’uso di wxString consente di passare stringhe alla libreria e riceverne senza alcun processo di conversione. Infine, wxString implementa il 90% dei metodi STL di std::string, quindi chiunque abbia familiarità con std::string può usare la wxString senza alcuna curva di apprendimento.


Uso di wxString


L’uso di wxString nelle applicazioni è semplicissimo. Ovunque si userebbe normalmente std::string o la propria implementazione preferita di stringa, si usa invece wxString. Tutte le funzioni che accettano argomenti stringa dovrebbero accettare const wxString& (che rende le assegnazioni alle stringhe all’interno della funzione più rapide a causa del conteggio dei riferimento [reference counting]), e tutte le funzioni che restituiscono stringhe dovrebbero restituire wxString, che rendono sicure le restituzioni delle variabili locali.

Dato che i programmatori C e C++ hanno familiarità con la maggior parte dei metodi delle stringhe, si è omessa quella che sarebbe stato un lungo riferimento alle API per wxString. Si consulti la documentazione delle wxWidgets per wxString, che forniscono un elenco completo di tutti i suoi metodi.

Si noterà che talvolta wxString ha due o più funzioni che fanno la stessa cosa. Per esempio, Length, Len, e length restituiscono tutte la lunghezza della stringa. In tutti i casi di duplicazione, si raccomanda fortemente l’uso di metodi compatibili con std::string. Questo renderà il codice più familiare ad altri programmatori C++ e cosentirà il riutilizzare lo stesso codice sia nelle wxWidgets che in altri programmi, dove si possa eseguire un typedef di wxString come std::string. Inoltre, le wxWidgets cominceranno ad utilizzare std::string nel prossimo futuro, in modo che tali metodi renderà i programmi più compatibili (anche se i metodi della wxString verranno supportati per un certo tempo per compatibilità col regresso).

wxString, Caratteri, e Stringhe Letterali


Le wxWidgets hanno un tipo wxChar che mappa sia char che wchar_t a seconda della configurazione della build dell’applicazione (Unicode o ANSI). Come già menzionato, non c’è necessità di separare i tipi di stringhe char e wchar_t in quanto wxString conserva le stringhe col tipo base C appropriato. Ogni volta che si lavora direttamente con le stringhe che si intendono usare con una classe delle wxWidgets, si usa wxChar anziché direttamente char o wchar_t. In questo modo ci si assicura la compatibilità sia con la configurazione della build ANSI che con quella Unicode senza complicate condizioni del preprocessore.

Quando si usano le wxWidgets con Unicode abilitato, le stringhe letterali standard non sono il tipo corretto: una stringa letterale non modificata è sempre di tipo char*. Per usare una stringa letterale in modalità Unicode, questa dev’essere una costante wide character, solitamente segnata come una L. Le wxWidgets forniscono la macro wxT (identica a _T) per avvolgere [wrap] le stringhe letterali ed usarle con o senza Unicode. Quando non è abilitato Unicode, _T è una macro vuota, ma con Unicode abilitato, aggiunge la L necessaria affinché la stringa letterale diventi una costante stringa wide character. Per esempio:


wxChar ch = wxT('*');

wxString s = wxT("Hello, world!");

wxChar* pChar = wxT("My string");

wxString s2 = pChar;
Per ulteriori dettagli sull’uso di Unicode nelle proprie applicazioni, si veda il Capitolo 16, "Scrivere Applicazioni Internazionali".

Conversioni Base da wxString a Puntatore C


Dato che ci possono essere dei casi in cui si deve accedere ai dati di una wxString come un tipo C per l’elaborazione a basso livello, le wxWidgets forniscono diverse funzioni di accesso:

  • mb_str restituisce una stringa C rappresentazione della stringa, un const char*, a prescindere dall’abilitazione dell’Unicode. In modalità Unicode, la stringa viene convertita, e si possono perdere dati.

  • wc_str restituisce una rappresentazione wide character della stringa, un wchar_t*, a prescindere dall’abilitazione dell’Unicode. In modalità ANSI, la stringa viene convertita in Unicode.

  • c_str restituisce un puntatore ai dati della stringa (const char* in modalità ANSI, const wchar_t* in modalità Unicode). Non c’è alcuna conversione.

Si può convertire tra std::string e wxString tramite c_str, in questo modo:
std::string str1 = wxT("hello");

wxString str2 = str1.c_str();

std::string str3 = str2.c_str();
Una trappola nell’uso di wxString è rappresentata dall’operatore di conversione implicita a const char *. Si consiglia di usare c_str per indicare chiaramente quando si deve fare la conversione. Il pericolo di questa conversione implicita si può vedere nel seguente frammento di codice:
// converts the input string to uppercase, outputs it to the

// screen, and returns the result (buggy)

const char *SayHELLO(const wxString& input)

{

wxString output = input.Upper();
printf("Hello, %s!\n", output);
return output;

}
Ci sono due brutti bug in queste quattro righe. Il primo è la chiamata alla funzione printf. La conversione in una stringa C è fatta automaticamente dal compilatore nel caso di funzioni come puts in quanto l’argomento di puts è risaputo essere di tipo const char *. Tuttavia, questo non viene fatto per printf, che è una funzione con un numero variabile di argomenti il cui tipo è sconosciuto. Una chiamata a printf può fare qualcosa d’altro (incluso mostrare la stringa corretta sullo schermo), sebbene il risultato più probabile sarà un crash del programma. La soluzione consiste nell’usare c_str:
printf(wxT("Hello, %s!\n"), output.c_str());
Il secondo bug è che la variabile restituita di nome output non funziona. Viene ancora usato il cast implicito, quindi il codice si compila, ma restituisce un puntatore ad un buffer appartenente ad una variabile locale che viene cancellata all’uscita della funzione. La soluzione a questo problema è semplice: la funzione deve restituire una wxString anziché una stringa C. Il codice corretto è simile a questo:
// converts the input string to uppercase, outputs it to the

// screen, and returns the result (corrected)

wxString SayHELLO(const wxString& input)

{

wxString output = input.Upper();
printf(wxT("Hello, %s!\n"), output.c_str());
return output;

}


Funzioni Stringa C Standard


Dato che la maggior parte dei programmatori usano stringhe di caratteri, la libreria C standard fornisce alcune funzioni per lavorare con esse. Sfortunatamente, alcune di queste hanno un comportamento poco intuitivo (come strncpy, che non sempre termina la stringa risultante con un NULL) o vengono considerate insicure per dei possibili sconfinamenti [overflow] del buffer. Inoltre, delle utilissime funzioni non sono affatto standard. Ecco il perché oltre a tutte le funzioni wxString, ci sono alcune funzioni stringa globali che tentano di rimediare a questi problemi: wxIsEmpty controlla se la stringa è vuota (restituendo true per puntatori NULL), wxStrlen gestisce correttamente i NULL e restituisce per esse 0, e wxStricmp è una versione indipendente dalla piattaforma della funzione di confronto tra stringhe case-insensitive nota come stricmp o strcasecmp su diverse piattaforme.

L’header "wx/string.h" definisce anche le funzioni wxSnprintf e wxVsnprintf che si dovrebbero usare invece della pericolosa sprintf standard. Le funzioni "n" usano snprintf, che esegue un controllo della dimensione del buffer quando possibile. Si può usare anche wxString::Printf senza preoccuparsi della vulnerabilità che si trova solitamente in printf.


Conversione da e verso Numeri


Spesso i programmatori hanno bisogno di conversioni tra stringhe e rappresentazioni numeriche dei numeri, come quando si elabora l’input dell’utente o si mostra il risultato di un calcolo.

ToLong(long* val, int base=10) tenta di convertire la stringa in un intero con segno in base base. Restituisce true in caso di successo, nel qual caso il numero è contenuto nella locazione indicata da val, oppure false se la stringa non rappresenta un numero valido nella base data. Il valore di base dev’essere tra 2 e 36, inclusi, o un valore speciale 0, che indica di applicare le solite regole dei numeri C: Se il numero inizia con 0x, è considerato essere in base 16; se inizia con 0-, lo si considera in base 8, ed in base 10 negli altri casi.

ToULong(unsigned long* val, int base=10) funziona identicamente a ToLong, solo che la stringa viene convertita in un intero senza segno.

ToDouble(double* val) tenta di convertire la stringa in un numero a virgola mobile. Restituisce true in caso di successo (il numero è contenuto nella locazione indicata da val) o false se la stringa non rappresenta un numero.

Printf(const wxChar* pszFormat, ...) è simile alla funzione standard C sprintf, e consente di immettere informazioni in una wxString con la stringa di formattazione C standard. Viene restituito il numero di caratteri scritti.

static Format(const wxChar* pszFormat, ...) restituisce una wxString contenente i risultati della chiamata a Printf con i parametri passati. Il vantaggio di Format su Printf è che Format si può usare per aggiungere ad una stringa esistente:
int n = 10;

wxString s = "Some Stuff";

s += wxString::Format(wxT("%d"),n );
operator<< si può usare per accodare un int, un float, o un double ad una wxString.

wxStringTokenizer


wxStringTokenizer aiuta a suddividere una stringa in un certo numero di blocchi [token], sostituendo ed espandendo la funzione C strtok. Per usarla, si crea un oggetto wxStringTokenizer e gli si dà la stringa da scomporre ed i delimitatori che separano i tokens. Per default, si usano spazi vuoti. Quindi si chiama ripetutamente GetNextToken finché HasMoreTokens restituisce false.
wxStringTokenizer tkz(wxT("first:second:third:fourth"), wxT(":"));

while ( tkz.HasMoreTokens() )

{

wxString token = tkz.GetNextToken();

// process token here

}
Per default, wxStringTokenizer funzionerà allo stesso modo di strtok se la stringa dei delimitatori contiene solo caratteri spazio. Diversamente dalle funzioni standard, però, restituirà dei tokens vuoti se appropriati per altri delimitatori diversi da spazio. Questo è utile per analizzare dati rigorosamente formattati dove il numero di campi è fisso ma alcuni di essi possono essere vuoti, come nel caso di file di testo tab- o comma-delimited.

Il funzionamento di wxStringTokenizer è regolato dall’ultimo parametro del costruttore, che può essere uno di questi:



  • wxTOKEN_DEFAULT: Il funzionamento di default come descritto precedentemente; lo stesso di wxTOKEN_STRTOK se la stringa del delimitatore contiene solo uno spazio vuoto, e lo stesso di wxTOKEN_RET_EMPTY negli altri casi.

  • wxTOKEN_RET_EMPTY: In questa modalità, verranno restituiti i tokens vuoti in mezzo alla stringa. Quindi a::b: verranno suddivisi in tre a, "", e b.

  • wxTOKEN_RET_EMPTY_ALL: In questa modalità, verranno restituiti anche i token in coda (dopo l’ultimo carattere delimitatore). a::b: contiene quattro tokens: lo stesso di wxTOKEN_RET_EMPTY ed un’altra vuota come quest’ultima.

  • wxTOKEN_RET_DELIMS: In questa modalità, viene aggiunto il carattere delimitatore dopo la fine del token corrente (eccetto che per l’ultimo token, che non ha delimitatore in coda). Altrimenti, è la stessa modalità di wxTOKEN_RET_EMPTY.

  • wxTOKEN_STRTOK: In questa modalità, la classe funziona esattamente come la funzione standard strtok. Non vengono restituiti tokens vuoti.

wxStringTokenizer ha due utili funzioni di accesso:

  • CountTokens restituisce il numero di tokens restanti nella stringa, restituendo 0 quando non ci sono più tokens.

  • GetPosition restituisce la posizione corrente del tokenizer nella stringa originale.

wxRegEx


wxRegEx rappresenta un’espressione regolare. Questa classe fornisce il supporto alla ricerca e sostituzione per le espressioni regolari. wxRegEx è sviluppata o sulla libreria di sistema (se è disponibile e c’è il supporto per le espressioni regolari POSIX, che è il caso della maggior parte delle moderne varianti Unix, incluso Linux e Mac OS X) oppure usa la libreria inclusa di Henry Spencer. Le espressioni regolari, come definite da POSIX, esistono in due varianti: estese e normali. La libreria inclusa aggiunge anche una modalità avanzata, che non è disponibile quando si usa la libreria di sistema.

Su piattaforme dove è disponibile la libreria di sistema, il default consiste nell’usare la libreria inclusa per le build Unicode, e la libreria di sistema negli altri casi. Si tenga in mente che Unicode è totalmente supportato solo dalla libreria inclusa. È possibile bypassare il default nel building delle wxWidgets. Quando si usa la libreria di sistema in modalità Unicode, le espressioni ed i dati vengono tradotti nella codifica di default a 8 bit prima di essere passati alla libreria.



wxRegEx si usa come si userebbe un processore di espressioni regolari POSIX. Data la natura avanzata e gli usi specialistici delle espressioni regolari, si faccia riferimento alla documentazione delle wxWidgets per una discussione completa ed i riferimenti alle API.



Condividi con i tuoi amici:
  1   2   3   4   5


©astratto.info 2019
invia messaggio

    Pagina principale