Newsgroup: it.comp.lang.c++
Titolo: Puntatore ad array bidimensionali

Salve a tutti, ho il seguente problema.
Un software che sto scrivendo deve contenere al suo interno un certo
numero di tabelle di look-up, implementate come array costanti a due
dimensioni:
const double pippo[3][5] = { ... };
const double ciao[64][2] = { ... };
const int hello[256][2] = { ... };
const int world[1024][4] = { ... };
questi array sono contenuti all'interno di un file, diciamo costanti.h
Poi ho una classe che deve utilizzare alcune di queste tabelle in base
al valore di un certo parametro; la mia idea era prevedere dei dati
membro della classe di tipo:
const double** pointer_one;
const int** pointer_two;
e inizializzare questi puntatori nel costruttore di classe in modo che
puntino alle tabelle associate ad un determinato flag che io passo
alla funzione. La cosa, purtroppo non funziona, in quanto il
compilatore rileva una inconsistenza dei tipi double** e double[3][5]
e cosi' via.
La mia domande e', dunque, se avete qualche di come poter approcciare
diversamente il problema

Usa delle std::map e dei puntatori o reference alle mappe.
Ciao,
Nicola

 e cosi' via.
Tieni ovviamente conto del suggerimento di Nicola. Ma eccoti comunque un
esempio funzionante con il tuo sistema:
#include <iostream>
#include <iomanip>
int main()
{
    int Tabella1[ 10 ][ 10 ];
    int Tabella2[ 10 ][ 10 ];
    for ( int i = 0; i < 10; ++i )
        for ( int j = 0; j < 10; ++j )
        {
            Tabella1[ i ][ j ] = ( i + 1 ) * ( j + 1 );
            Tabella2[ i ][ j ] = ( i + 1 ) * ( j + 1 ) * 10;
        }
    int ( *p )[ 10 ] = Tabella2;
    for ( int i = 0; i < 10; ++i )
    {
        for ( int j = 0; j < 10; ++j )
            std::cout << std::setw( 4 ) << p[ i ][ j ] << ' ';
        std::cout << '\n';
    }
    return 0;
}
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

 
ehm, ci avevo provato e non funzionava perche'... non mettevo le
parentesi tonde attorno al puntatore... ok, ho vinto un premio per la
stupidita'? :)
In realta' ho ancora un problema relativo ad alcune tabelle la cui
seconda dimensione non e' costante, ma dipende dalla variabile di
selezione. CI sto lavorando su.
Poi vi pongo un'altra domanda, che meriterebbe un nuovo titolo per il
post. In realta' io sono un finto programmatore C++, in quanto
utilizzo un C sporcato con classi ed altre cose del C++: insomma
appartengo a quella razza che voi del newsgroup penso miriate ad
eliminare (o educare) :)
Secondo voi, l'utilizzo delle classi vector, map, etc. quanto puo'
inficiare le performance di un programma (dato per scontato che,
invece, migliora lo stile e l'efficacia della programmazione)? Nel mio
software faccio un uso pesante di matrici, vettori, tavole di look-up,
etc tutto (o quasi) allocato dinamicamente.
Tenete conto che questo software serve a fare delle simulazioni per
applicazioni scientifiche, ed una simulazione dura anche qualche
settimana su una macchina Linux con doppio Xeon (ed il programma viene
lanciato in modo da sfruttare a piena potenza entrambi i processori):
insomma, per me le perfomance non sono un aspetto trascurabile :)
Vi chiedo commenti basati sulla vostra esperienza di programmatori.
Grazie ancora.
nico

 nico
Ciao,
Non ho seguito il thread, ma mi sono soffermato solo su questa tua ultima
domanda che merita una risposta forse generale ma definitiva in quanto
troppo spesso la si sente porre da programmatori di tutti i linguaggi che
sono spaventati dall'overhead che l'uso delle librerie standard dei vari
linguaggi si presume (erroneamente) possa caricare sui nostri programmi.
Il problema non è solo in C++, ma per rimanere vicino a noi ti faccio solo
l'esempio di chi in C preferisce costruire una propria routine per copiare
le stringhe (char*, in stile C) al posto di usare strcpy oppure strncpy e
via dicendo.
Va detto che le librerie standard (quelle più diffuse e di provata
affidabilità) sono costruite da PROFESSIONISTI che conoscono tutti i trucchi
del mestiere e sono studiate per ottimizzare al massimo i tempi di
esecuzione, la prevedibilità e la robustezza.
Affrontiamo solo il tema della efficienza dicendoti qualcosa sulle librerie
C e C++ istallate sulla mia Linux box e che sono la GNU/libc e la
GNU/libstdc++-v3.
Esse sono studiate appositamente per l'ambiente su cui girano e ne traggono
fino all'ultima goccia tutte le potenzialità del sistema operativo e del
compilatore (gcc) per le quali sono scritte.
Soprattutto bisogna attenzionare il compilatore per due motivi:
1) Normalmente il programmatore non utilizza le estensioni al linguaggio
tipiche di un compilatore perchè vuole che il suo codice sia compilabile
anche da altre coppie di compilatori/assemblatori e quindi di solito si
cerca di scrivere codice standard.
Invece chi scrive librerie come le suddette, volendone massimizzare
l'efficenza e sapendo che saranno compilate da uno specifico compilatore,
introduce nel codice parecchie soluzioni che incrementano velocità di
esecuzione e diminuiscono lo spazio occupato in memoria.
Come? Ad esempio inserendo codice Assembly in-line nei punti critici, oppure
usando direttive come "prefetch" che causa la lettura dalla cache o dalla
memoria (in caso di 'cache miss') di una specifica porzione di codice o dati
da introdursi nella pipeline di esecuzione prima ancora che la precedente
operazione sia conclusa.
La direttiva "prefetch" di gcc, ad esempio non esaustivo, si usa nello
scorrimento di una "linked list" per ottenere il prossimo nodo mentre ancora
si sta elaborando il precedente. Oppure la direttiva "likely/unlikely" che
ottimizza l'esecuzione delle "if".
Ora non voglio elencare tutte le features del compilatore che sono spremute
a fondo dagli scrittori di librerie ma basti sapere che ci sono decine di
strumenti che normalmente il programmatore applicativo non usa.
2) Oltre alle direttive e all'Assembly in-line ci sono una miriade di flags
e opzioni varie da attivarsi o disattivarsi al momento della compilazione. E
non parlo solo dei superusati "-On" oppure "-march=processor" ma di cosine
più delicate come "-fomit-frame-pointer", "-fprefetch-loop-arrays",
"-funsafe-math-optimizations", " -fbranch-probabilities" e una cinquantina
di altre come queste che sono PERICOLOSISSIME da usarsi se non si conoscono
a fondo.
Quindi ci troviamo a disposizione del codice che più ottimizzato di così non
ce n'è! A scanso di equivoci, non vorrei che qualcuno pensasse che comunque
dipende solo da questi ultimi due punti: ricordo che come prima cosa ho
citato la professionalità e grande competenza in MATERIA di LINGUAGGIO
stesso, di ALGORITMI e di STRUTTURE DATI (tutto ciò che viene prima ed è al
di fuori dei meccanismi offerti dal compilatore) da parte di coloro che
scrivono le librerie.
IN CONCLUSIONE se in un tuo programma hai bisogno di qualcosa che si
comporti come un array dinamico la scelta migliore è quella di usare
std::vector, se hai bisogno di linked lists usa std::list e così via, con la
certezza che comunque tu rifacessi da zero il codice e lo compilassi al
solito modo non otterresti mai una qualità superiore.
ANCORA UN PENSIERO: ammettiamo anche che qualcuno abbia la competenza per
ricreare da zero e a parità di efficienza i containers e le funzioni di
libreria necessarie al proprio programma sarebbe comunque la cosa peggiore
che si possa immaginare di fare al proprio prodotto, perchè gli si
VIETEREBBE la possibilità di usufruire delle funzionalità delle librerie
standard di qualsiasi altro ambiente (hardware, sistema operativo,
compilatore) ove venisse portato (ricordo che le ottimizzazioni di cui sopra
non sono portabili e quindi ci si deve affidare alla libreria dell'ambiente
di destinazione)
Buon lavoro,
fabio de francesco
(fabiomdf)
PS.: Non sarebbe il caso di scrivere qualcosa sulle FAQ ufficiali a
proposito della remora che molti hanno nell'usare la libreria standard?
 
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 proposito della remora che molti hanno nell'usare la libreria standard?
Ti va di buttare giù qualcosina? Però prima vorrei dire una cosa al
riguardo dell'ottimizzazione: una persona di cui mi fido mi ha detto che
ha riscontrato perdita di efficienza rispetto al C a causa
dell'indirezione dovuta al puntatore this e relativa virtual table. E'
possibile?



 


 virtuali e come sappiamo è necessaria per il binding dinamico.
In effetti ho sbagliato a citare la virtual table che non c'entra
niente. Risolviamo allora il problema dell'indirezione di cui sopra.
Convincimi che non c'è e dimostramelo, se possibile, con un breve codice
compilabile. Io l'ho già fatto ed ho trovato piccolissime differenze. Ma
poi l'amico di cui sopra mi ha detto che l'aveva fatto anche lui e poi
si è accorto che, quando il codice diventa più complesso, l'overhead
diventa importante.
EMG


 EMG
Saluti e buon lavoro,
fabio de francesco
(fabiomdf)


 vari o, meglio ancora, implemento un albero binario?
Ma dipende dalla mappa: se ti serve una mappa tipo:
map<string, string>  puo' anche darsi, ma se ha bisogno di qualcosa di piu
articolato come:
map<string, map<string, vector<T> >
dove T potrebbe essere chissa' che tipo, realizzare tutto a mano credo sia
seccante, complesso, e facilmente si potrebbero fare errori (specie logici,
che emergono solo in casi particolari, mandando in crash tutto :/).
Secondo me, quando si mette mano ai puntatori per realizzare strutture dati
come mappe, e' meglio delegare il piu possibile le operazioni al sistema, in
questo caso alla STL.
Questo e' quello che penso, magari sbaglio, non so... aspetto repliche :)
Ciao

 l'efficienza/inefficienza dell'uso del '*this' contro cosa di preciso?
La persona di cui sopra mi ha detto che ha semplicemente confrontato le
due versioni del programma, con e senza this.


 implementare solo in quei punti nuovo codice.
Sono d'accordo. Anche con il resto delle risposte.


 EMG
Ciao,
Vedo quindi che non siamo d'accordo, nč con Noixe nč con te... Questo
significa che non vi ho convinto con la mia tesi sull'efficienza delle
librerie standard (C e/o C++ che siano) rispetto alle strutture dati ed
algoritmi "fatti in casa".
Credevo di avere sufficentemente approfondito il concetto per cui č molto
improbabile che questi ultimi possano superare in efficienza le suddette.
Invece leggo da Noixe:"Credo che l'efficienza debba essere *realmente* un
esigenza per scegliere di scrivere..."; quindi asserite esattamente
l'opposto: gli algoritmi e le strutture dati fatti da se evitano l'overhead
imposto dalla libreria standard che invece crea colli di bottiglia!
Perň continuo a non capire da dove vengano fuori queste comparazioni di
efficienza. Nessuno di voi ha postato del codice che, per esempio, gestisce
le linked lists piů velocemente di una qualsiasi implementazione a caso
della Standard C++ Library, diciamo la GNU/libstdc++-v3. Dove sono queste
analisi? Documenti stampati o in rete? (Non credo sia sufficiente dire:"Io
la penso cosě". Bisogna anche motivare la sentenza, come spero di avere
fatto in precedenza).
In aggiunta alla tesi riporto alcuni estratti (ancora un paio, oltre al
precedente) dal testo di Bjarne Stroustrup, The C++ Programming Language,
rispettivamente da pag 8 e 430:
"Feature that would incur run-time or memory overheads, even when not used,
were avoided in the design of C++".
"The roles of a standard library impose several constraints on its design.
The facilities offered by the C++ standard library are designed to be:
[1]... [2]... [3] Efficient enough to provide genuine alternatives to
hand-coded function, classes and templates in the implementation of further
libraries. [4]... [5]... [6]... Convenient,efficient and reasonably safe for
common uses. [7]... [8]... [9]... [10]... [11].".
E poi continua a pagina 431(la parte piů importante di tutte sull'efficienza
e che pare fatta a posta per rispondere ai dubbi/certezze di cui ai nostri
discorsi):
"The standard library is not just required to perform its tasks. It must
also perform them efficiently enough not to tempt users to supply their own
mechanism.".
Addirittura poi continua dicendo che, se la standard library non fosse cosě
efficiente, gli implementatori di strumenti software molto avanzati si
sentirebbero forzati a by-passare la libreria standard per rimanere
competitivi.
Saluti,


 competitivi.
E chi ti dice che non lo facciano? Se lo fanno, non danno poi certo il
codice in giro, non ti pare?


 competitivi.
Si, ricordo questo paragrafo. Infatti qui siamo nel caso in cui il software
sia sviluppato da un team (anche molto grande) di programmatori. E se leggi
il mio post precedente, proprio all'inizio esprimo il mio parere in merito,
ovvero favorevole all'uso della STL.
Ciao

algoritmi "fatti in casa".
Io sono sostanzialmente d'accordo con te sull'efficienza della
libreria standard. Esattamente come sono convinto dell'efficienza
delle librerie standard di altri linguaggi (in effetti io sono
parecchio appassionato di Python, per dire... e nella maggior parte
dei casi di colli di bottiglia non ne ho incontrati).
Tuttavia non dimentichiamo una cosa. La libreria standard del C++ e'
scritta con in mente la maggior generalita' sensata (e spesso e' anche
la maggiore possibile).
Molti algoritmi/contenitori possono essere riscritti/specializzati
tenendo conto di ipotesi piu' restrittive. In questo modo si ha
effettivamente un guadagno di efficienza.
Questo non vuole dire che la libreria standard sia inefficiente. E' la
libreria piu' efficiente possibile (o tenta di esserlo) tenendo conto
del suo livello di generalita'.
Rinunciando a generalita', facendo piu' assunzioni, si puo'
ottimizzare ancora di piu'.
Chiaramente quando e' necessario (e magari scrivendo codice che si
comporti come quello della libreria... magari semplicemente
specializzando "a mano" certi algoritmi templatici e simili).
Quindi no a riscrivere le cose perche' si pensa di essere piu' veloci.
A meno che non si sa esattamente quello che si sta facendo.





Ciao,
Ottima analisi da parte tua. In effetti la 'teoria' ci dice che la
'generalizzazione' ha un costo più alto della 'specializzazione'. E non
possiamo fare a meno di essere d'accordo con 'essa'.
Di fatto però non si può assumere a priori che la semplice scrittura di
codice specializzato risulti in effetti in strumenti software più
efficienti.
Prendo per buoni soprattutto (ma non esclusivamente) gli ultimi due
paragrafi del tuo post estendendone i concetti: "A meno che non si sappia
cosa si sta facendo" significa sapere e potere comparare, codice alla mano e
con strumenti di profiling avanzato, le differenze di efficienza tra i due
(libreria standard e hand-made program). Probabilmente il modo migliore di
creare un'alternativa più specializzata e di consequenza (sulla carta) più
efficiente è proprio il metodo che tu suggerisci sul modificare a mano il
sorgente della libreria dove si può fare e conviene se è stata già assunta
la mancanza di necessità di certe generalizzazioni.
A proposito della libreria standard di Python (e delle librerie standard di
tutti i linguaggi 'well-formed') ho già detto cosa ne penso in un precedente
post dello stesso thread: estendo 'in generale' la validità di quanto
affermato sul C++ anche a tutte le librerie standard di tali linguaggi.
Però temo di avere qualche dubbio proprio su quella del Python se è vero
quanto mi sembra di ricordare. Mi sembra che l'interprete del Python è
scritto in C, mentre invece la sua libreria è scritta nello stesso
Python(?). Quindi il codice della libreria è interpretato di volta in volta?
Se è così ne consegue (forse(?)) che se fosse riscritta in C o C++ o ancora
altri linguaggi 'low-level' (e compilati) guadagnerebbe potenzialmente in
efficienza. Sarà realmente così? Non lo so.


 la mancanza di necessità di certe generalizzazioni.
Una puntualizzazione. Il modo migliore per migliorare le prestazioni in
un caso specifico non e' tanto modificare a mano una libreria
esistente, quanto lo scegliere un algoritmo e/o una struttura dati
completamente diversa, le cui caratteristiche prestazionali si adattino
meglio al problema in esame. Tentare di ottimizzare una parte della
libreria standard e' secondo me una perdita di tempo.
Ciao,
Nicola

 Python(?). Quindi il codice della libreria è interpretato di volta in volta?
Allora... è scritta in parte in C e in parte in Python. Alcune cose
hanno anche la doppia implementazione, quella in C e quella in Python
(quella in C serve per l'interprete CPython, scritto in ANSI C, mentre
quella in Python per facilitare quelli che scrivono "altri" interpreti
-- IronPython [C#] , Jython [Java], pypy [Python] -- ).
Per esempio se ricordo bene il codice delle liste e dei dizionari è
scritto tutto in C. Idem per le stringhe. I moduli dove la performance è
meno critica sono scritti in Python.
Comunque se vogliamo proseguire questo discorso possiamo spostarci su
it.comp.lang.python dove peraltro puoi trovare probabilmente risposte
più esaurienti.
Comunque un buon modo per capire (sempre se ricordo bene) se un modulo è
'compilato' (quindi ci finirebbe dentro anche uno scritto in C++ o in
Fortran) o scritto in Python si può usare la shell interattiva iPython.
Chiamando un metodo/oggetto seguito da ? si ottiene l'help. Se seguito
da ?? si ottiene il codice python (se presente). Empiricamente puoi fare
delle prove e avere qualche informazione in più.
Poi chiaramente ci sono anche moduli disponibili in "versione standard"
scritta in Python, ma di cui è presente anche un'ottimizzazione scritta
in C. Esempio StringIO/cStringIO.
-- 
[ RiK0                                ]
[ Go away! The internet is full!      ]
[ Non credo negli schemi non vincenti ]

 Nicola
Ciao,
A scanso di equivoci, ribadisco la mia assoluta convinzione che le più
diffuse e apprezzate implementazioni della libreria standard del C++ hanno
il codice più efficiente che si possa
immaginare per il lavoro che è richiesto debbano svolgere. E mi pare di
avere tentato di svolgere e dimostrare questo tema con una sufficente
quantità di argomentazioni tutte a sfavore del codice fatto in casa...
Il post sul quale hai "puntualizzato" rispondeva solo ad un particolare CASO
LIMITE dove si immaginava di assumere a priori di non avere bisogno delle
"generalizzazioni" offerte dalla libreria (vedi templates, iteratori
costanti e non costanti e tante altre 'cosine' (scherzo!) che tutti noi
conosciamo). E immaginavamo anche di seguire la tesi (tra l'altro provata in
computer science) che le "generalizzazioni" hanno un costo computazionale
maggiore delle "specializzazioni".
Presa per 'necessaria' una scelta (opinabile) di questo tipo da parte di
qualcuno, mi sembra che la cosa più veloce da farsi è prendere il sorgente
della implementazione della tua libreria standard C++ preferita e (licenza
permettendo) ricopiarti il codice togliendo col bisturi tutto ciò che sei
convinto non serve al tuo scopo.
Per ultimo, una risposta al contenuto del tuo post:
Se un contenitore, un algoritmo o qualsiasi altro strumento necessario al
tuo lavoro non è già presente in libreria il problema di scegliere tra
strumento standard si o strumento standard no NON esiste più, ed è più che
ovvio che dovrai costruirti da solo la feature che non c'è.
Voglio dire che se come dici hai bisogno di "... scegliere un algoritmo o
una struttura dati completamente diversa..." ciò può derivare solo dalla
mancanza di tale strumento in libreria. Pertanto valutazioni comparate
vengono a perdere di significato.
Buon lavoro,


 vengono a perdere di significato.
No. Puo' dipendere semplicemente dal fatto che il tuo problema puo'
presentare caratteristiche specifiche che rendono gli strumenti della
libreria men che ottimali per i tuoi scopi.
Ciao,
Nicola

 Nicola
