Newsgroup: it.comp.lang.c++
Titolo: "solidità" della STL

Ciao a tutti,
Ho imparicchiato il C++ più o meno ai tempi della
seconda edizione dello Stoustrup ('93) e poi per
diverso tempo l'ho usato per necessità minime.
All'epoca mi scrissi da me qualcosa che come idea
poteva essere una versione iper-rozza dell'attuale STL
e su quello ho lavorato. Ma di librerie standard non
avevo sentito parlare o mi pare se ne iniziasse allora
a parlare.
Ora, dopo diversi anni e connesso alla rete, ho
scoperto la STL e vorrei "migrare" ad essa, tanto più
che sto riprendendo a usare il C++ da poco, con un
buco nero temporale di quasi dieci anni. Visto che ora
esiste qualcosa fatta da gente che di librerie ne
capisce 100.000 volte più di me, sarebbe il caso che
la adottassi e mi si pone il problema di pensare in
termini lunghi. Non vorrei fare una prima complicata
migrazione per poi scoprire che le evoluzioni della
STL mi costringeranno a modificare nel tempo programmi
e modi di pensare. Quel che vi chiedo è: la STL è
ormai matura e abbastanza stabile e diffusa da poterci
far conto? Lo sarà in futuro? Prospettive in embrione
di cui si discute nella comunità?
Preferirei il tam-tam della comunità a dicharazioni
più o meno ufficiali che magari non riflettono lo
stato delle cose. Non devo tirare il collo al
linguaggio né fare cose strane (credo che il 90% di
quel che mi serve lo farò con il template <vector.h>).
Mi interessa invece essenzialmente portabilità e
"stabilità" nel tempo degli strumenti a
cui mi devo appoggiare.
Ovviamente ogni riferimento a siti, materiali e altre
librerie più o meno stabili e "accettate" saranno
utilissimi.
Grazie per ogni vostro commento e già che ci sono
auguri di buona Pasqua.
Apx.

 utilissimi.
La libreria Boost (che si basa sulla libreria standard) offre delle
estensioni interessanti e multipiattaforma.
http://www.boost.org/
-- 
LF

Grasssiieeee!!!! La risposta che mi serviva!
Apx.
PS - sì la <vector>, era ovviamente una svista!

 PS - sì la <vector>, era ovviamente una svista!
Non preoccuparti... ho voluto correggerti perchè l'eliminazione del .h dagli
header standard è appunto una "novità" delle ultime specifiche...:)
Comunque non fermarti ai vector, ci sono molte cose utili nella libreria
standard... come la classe string, map per gli array associativi...
-- 
LF

> Quindi fa parte del linguaggio, come "if" e "for"... piů matura di
cosě...:)
Matura e completa oserei dire. Dopotutto ci sono i vettori e ci sono gli
auto_ptr... E ci sono i vettori di auto_ptr... Ah... No.... Quelli non ci
sono! Perň c'č lo splice delle list che viene sempre eseguito in un tempo
lineare! (anche se non richiesto dallo standard) (quest'ultima č una critica
che possono comprendere solo quelli che sono molto addentro alle discussioni
sulla libreria STL).
Senza comunque dimenticare un abbondante uso di operatori di copia!
Usando le STL puoi far diventare un ottimo programma veloce come un
programma scritto in VB. Sono lo strumento con cui č piů facile (insieme
agli stream) combinare disastri in termini di prestazioni. Sconsiglio il
loro uso a chiunque non ne sia cosě tanto addentro da non averne in ogni
caso bisogno.
--- bye

caso bisogno.
di questo andrebbe fatto qualche esempio, magari, che i vector e le
list siano lente bisogna dimostrarlo ampiamente...
e poi, VB? sei proprio sicuro di voler accomunare il c++ + std al vb?
-- 
]\/[ad]\/[age (
www.mindreamz.net
)
"Un Maestro insegue semplicemente la sua visione di Eccellenza in
qualunque cosa sta facendo e lascia agli altri decidere se sta 
lavorando o giocando. A lui sembra sempre di fare entrambe." - Anonimo

 caso bisogno.
Ma certo, facciamo tutto con i char* e riempiamo il nostri programmi di
buffer-overflow...
-- 
LF

 e poi, VB? sei proprio sicuro di voler accomunare il c++ + std al vb?
Faccio un esempio banale. Tu programmi in C++ e quindi cosa usi? Usi le
classi, mi sembra ovvio! Peccato che, dato il funzionamento dei Vettori,
fare un Vector di classi sia un suicidio (è ovvio che il vector non sia
pensato per essere ridimensionato spesso, ma mentre un vector di POD è
decentemente veloce, un vector di non-POD è lentissimo). Se ti viene in
mente di fare una length di una lista puoi solo sperare di essere in
un'implementazione in cui hanno deciso che il length ha una durata costante,
e non lineare (per dei litigi/delle incomprensioni interne). Inoltre, come
se non bastasse, ogni volta che tu inserisci un nuovo elemento in una
lista/vettore/??? viene eseguita un'operazione di copia (quindi tu crei un
elemento e poi crei una copia di quell'elemento. Lo standard, se ben
ricordo, non ha un comando per inserire un elemento "vuoto" in una posizione
X. Questo perchè (onestamente) non si potrebbe avere un comando "generico",
perchè non si può prevedere la sintassi di tutti i costruttori (un
costruttore potrebbe avere x parametri). Il fatto che almeno il 60% delle
volte un oggetto possa essere creato con il costruttore standard e poi
modificato "a mano" non è importante.). Infine c'è il problema (che si può
discutere se è un problema o no) che le string non sono reference-counted.
Normalmente questo non è un grave problema (è stato dimostrato che è un
problema solo se si fa cattiva programmazione...) Oppure se si fa:
string MiaFunzione(void)
{
    string pippo("Ciao");
    return pippo;
}
In questo caso banale un compilatore decente si accorgerà che pippo viene
creata solo per essere restituita, e quindi non userà il costruttore di
copia, ma farà un trucco e costruirà direttamente la stringa da restituire.
In casi più complessi invece potrebbe non succedere (c'è una regola che
adesso non mi ricordo, che dice se il compilatore può o non può fare questo
giochino "magico" ignorando gli effetti collaterali del distruttore di
pippo. Ora non me la ricordo). Il problema è che, in ogni caso, non è dato
sapere al programmatore se il compilatore riuscirà ad ottimizzare oppure no.
Chiaramente facendo
void MiaFunzione (string& pippo)
{
    pippo = "Ciao";
}
tutto si risolve... Ma qui si implica che l'utilizzatore conosca il
funzionamento delle stringhe del C++ :-)
Ci sono altri esempi... Se vai a cercare nei ng in inglese del C++ vedrai
delle guerre su questi argomenti che metà bastano.
--- bye

 If the position specified is greater than the size of the container, the
result is undefined.
Ora... Tutta 'sta sicurezza "garantita" io non la vedo :-)
Qui sta scritto che posso leggere dove non dovrei anche con i vector!
--- bye

 funzionamento delle stringhe del C++ :-)
Beh, mi sembra il minimo se uno vuol programmare in C++...:)
-- 
LF

 Ora... Tutta 'sta sicurezza "garantita" io non la vedo :-)
Infatti se vuoi la sicurezza garantita devi usare at(), che in caso di
sforamento lancia un'eccezione standard.
-- 
LF

 Beh, mi sembra il minimo se uno vuol programmare in C++...:)
Vedi che ti serve una conoscenza approfondita del C++? Se no fai danni, e se
ce l'hai molto spesso capisci che le STL non sono la soluzione perfetta. (io
avendo programmato con il VC++ devo dire che molto spesso le ATL sono
migliori. Da certi punti di vista sono state costruite in maniera più
intelligente (per esempio le liste/i vettori hanno la possibilità di avere
una classe che ne definisca i "tratti", in maniera che, da fuori, si possa
definire come effettuare la copia/lo spostamento degli elementi). Non sono
perfetti (gli auto_ptr delle ATL non hanno risolto un problema che invece
gli auto_ptr delle STL hanno risolto), ma per lo meno, non essendo
appesantititi da un processo burocratico dietro (la burocrazia dietro alle
STL è spaventosa), c'è sempre la speranza che migliorino più rapidamente).
--- bye

 sforamento lancia un'eccezione standard.
Lo so che devi usare l'at() (e qui si potrebbe discutere sul fatto che hanno
inserito cosě tanta "roba" nelle classi da farle esplodere. Due, dico DUE
operatori per prendere un elemento!)
--- bye

 rapidamente).
Purtroppo mi sa che se vuoi standardizzare una cosa all'ISO la burocrazia è
inevitabile...:(
-- 
LF

 dico DUE operatori per prendere un elemento!)
Boh... non capisco, ma cosa vorresti ? Hai un operatore [] che non esegue
controlli e quindi è più veloce, hai at() che perde un po' di tempo per i
controlli ma è sicuro... ognuno usa quello più adatto alle sue esigenze !!
-- 
LF

 anzi, memcpy è più veloce.
Ma in C++ è diverso! Se la tua classe rappresenta una risorsa del SO,
duplicarla significa chiedere al SO di duplicare la risorsa (con un tempo
diciamo elevato). Se invece a te basta spostare la tua classe in giro per la
memoria, di sicuro non te ne frega niente del SO.
Prendi una classe come la string. La string, nel caso più "semplice" può
essere immaginata come
class string {
    char *text;
    size_t lentext;
    size_t memallocated;
}
(in realtà è molto più complessa, ma facciamo finta che sia così).
Ora... Per duplicare la string tu devi: creare una nuova string vuota,
allocare una nuova text, copiarci dentro la vecchia text. Se invece tu devi
solo "spostare" la tua vecchia string in un'altra locazione di memoria, tu
sposterai semplicemente 12 bytes o giù di lì (sizeof(string)). Tu sposterai
la string senza spostare il suo "payload".
--- bye

 Tu sposterai la string senza spostare il suo "payload".
Ma che significa "spostare la tua vecchia string in un'altra locazione di
memoria" ? Significa che la nuova locazione di memoria "punta" alla vecchia
string !! Stesso discorso, i riferimenti servono proprio a questo !!
-- 
LF

 di cui si discute nella comunità?
Si, STL è potente e sopratutto affidabile.
Questi sono due buoni motivi per utilizzarla.
Parlando di prestazioni il discorso si complica un pò, io dirò la mia.
Chiaramente ogni volta che utilizziamo una libreria, anche se non ce ne
rendiamo conto, facciamo un patto con gli sviluppatori che l'hanno scritta.
STL è molto vasta e ha container e potenti algoritmi "per tutte le
stagioni".
Nella maggior parte delle nostre applicazioni non cambierà praticamente
nulla se i nostri oggetti verranno copiati o spostati una volta in più.
Quando non ce ne importa nulla o ce ne importa poco, allora non ci sono
motivi per non usare STL.
Quando le nostre applicazioni diventano critiche come richiesta di potenza
al calcolatore, allora, bisogna essere programmatori accorti e sapere (ma è
bene saperlo sempre) le differenze fra le varie strutture dati, i loro
costi/benefici e sapere anche quali algoritmi sono più efficienti per
lavorare sui nostri dati (discorsi che esula da STL). Questa conoscenza ci
aiuta a capire se è possibile usare STL con la massima efficienza (e spesso
si può, senza paventare tutte quelle copie di oggetti in giro per la
memoria) o se invece dobbiamo crearci un contenitore apposito per gestire
efficientemente i nostri dati.
In pratica STL è una soluzione chiavi in mano quasi sempre ottima per
gestire le cose. Solo conoscendo bene come funziona è possibile sapere
quando (e spesso è così) i suoi benefici superano il costo.
Ci sono tanti esempi di programmi velocissimi con STL e non, secondo me non
è questo che incide.
Dipende sempre da cosa vuoi fare e come lo vuoi fare.
E' sempre chi programma che deve, con le sua cultura, metterci dentro
qualcosa in più.
Le soluzioni sono tante, sta a chi è bravo trovare le migliori sotto diversi
punti di vista.
La cosa più importante, però, è scrivere programmi che funzionano. (sembra
banale ma molti si scrivono contenitori da soli per risparmiare un
microsecondo quando poi ne perdono dieci a leggere dati da un disco, poi il
programma presenta dei bug e vai a vedere che sono proprio problemi
d'allocazione in memoria).
Io ti consiglio di studiartele bene, poi vedi tu.

Qui sta scritto che posso leggere dove non dovrei anche con i vector!
Il problema e' che una riallocazione automatica e
ragionevolmente efficiente costa pochissime istruzioni
in C++ usando un std::vector (basta dichiararlo e
usare push_back). Scrivendo invece "alla C" la cosa
richiede un po' piu' di codice esplicito e il risultato
e' che -->per pigrizia<-- spesso un programmatore finisce
per scrivere "int a[10];" e usare "a[i++]=x" fregandosene
di fare controlli di sconfinamento.
Andrea

Grazie infinite di tutte le risposte, alcune lunghe e
dettagliate; tutte le ho trovate veramente utili.
Insomma, mi tocca studiare 'sto immenso vespaio...
povero me.
Ovviamente so che un minimo straccio di conoscenza è
necessaria. Ad esempio per "vector <...>" la
riallocazione conseguente al dimensionamento e la
relativa chiamata del costruttore di copia non me lo
farebbero mai usare per oggetti grandi. Per quanto il
template possa essere scritto da geni della
programmazione, immagino esistano limiti oggettivi a
quel che si può fare. Mi ingegnerò di approfondire la STL.
Un saluto!
Apx.

 delle guerre su questi argomenti che metà bastano.
Sui newsgroup *seri* per fortuna si parla di argomenti seri e di
problemi veri. Faresti bene ad informarti meglio prima di esprimere
opinioni.
Ciao,
Nicola

 STL è spaventosa), c'è sempre la speranza che migliorino più rapidamente).
Oppure, essendo soggetti a minori verifiche, che contengano piu'
errori concettuali.
Ciao,
Nicola

 standard specifica richiedere complessita' costante.
mi sembrava di avere letto sulla mailing list della stdlibc++ del gcc
dicevano che non e` necessario, ma piuttosto ''suggerito''.
dopo di che mi smentisco da solo vito che ndando a leggermi il sorgente,
*e` costante*.
questa interpretazione viene dal fatto che dice
''Those entries marked ''(Note A)'' should have constant complexity''
e size e` marcata ''(Nota A)'' e non semplicemente ''constant''.
ora... mettiamo tutto fra due bei tag <IIRC>, visto che il thread non lo
ho ritrovato... (e magari non parlava della lista... ) 
La domanda che mi pongo a parte questo e`... l'interpretazione dello
'should' e` corretta?
o meglio.. qualcuno ricorda riguardo a che contenitore la discussione
fosse riferita?
-- 
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it.
    - Brian W. Kernighan

 fosse riferita?
Sì. E' should. Il mondo si divide in due metà: quelli che hanno lo splice
sempre in tempo costante e quindi il size non è costante (al più può essere
costante a tratti, se si usa una variabile per salvarne una copia "cache"),
e quelli che hanno lo splice in tempo costante solo in alcuni casi ma in
altri no e che hanno il size in tempo non costante. Se ben ricordo è stata
la SGI la prima a usare questa seconda interpretazione (fatto dovuto (sempre
se ben ricordo, ma i commenti nei ng che avevo letto tempo fa dicevano così)
dal non aver letto con precisione la complessità richiesta da
splice(iterator, list<t, allocator>, iterator first, iterator last) che
serve per spostare un range di elementi e che, a differenza degli altri casi
di splice, non sempre è necessario venga eseguita in tempo costante)
--- bye