Newsgroup: it.comp.lang.c++
Titolo: Mascherare accesso ai dati ed array

Salve,
torno qui con un nuovo problema da niubbo sul C++ (tra l'altro, le FAQ di
questo NG vengono postate periodicamente o devo andarle a prendere da
qualche parte? Scorrendo l'elenco dei messaggi non le ho trovate).
Ho una classe che mi serve per mascherare l'accesso agli elementi contenuti
in un array, cosě che si possano solo leggere e non scrivere, in pratica,
tralasciando tutto quello che non serve:
class mArray {
    private:
        int *array[100][100];
    public:
        int get_el(int x, int y);
};
Siccome alcuni elementi in alcune coordinate dell'array non esistono (non
so, ad esempio chiamando array[0][0] punta a NULL (sě, lo so che in C++ non
si dovrebbe usare null)), non so come fare per dire al chiamante di get_el
che l'elemento in certe coordinate č nullo (non che vale 0, proprio che non
esiste).
Se io da get_el restituisco al posto di un int un int *, potrei tornare NULL
nel caso in cui l'elemento richiesto non esista, perň, nel caso di un
elemento esistente, il chiamante potrebbe modificare il valore contenuto
nell'array, perché ne conosce l'indirizzo.
D'altro canto, restituendo int, non ho alcun modo per distinguere un valore
esistente da uno non esistente.
In C++, qual č il metodo "canonico" per gestire situazioni di questo tipo?
Mi verrebbe in mente di copiare l'elemento e poi restituire un ptr alla
copia (oppure null se non esiste). Qualcuno mi ha consigliato di passare
come ulteriore argomento a get_el un ptr ad un bool, cosě se il valore
richiesto non esiste get_el setta a true quel bool, perň mi sembra troppo
poco elegante, anche perché vorrei che la chiamata a get_el somigliasse il
piů possibile all'accesso normale ad un elemento di un array.
Mille grazie,
Lanugo

piů possibile all'accesso normale ad un elemento di un array.
Wow, proprio nessuno ti ha consigliato le eccezioni?
Guarda che esistono :-)
Ciao
Domenico Barra
PS: Problemi con le NEWS appena risolti!

Guarda che esistono :-)
Ok, cercherň di capire come funziano.
Lanugo

chiedermi il perché, me l'hanno detto ed io mi fido :-)
Già, ma non capisco perché, quando il C++ offre una validissima soluzione ai
problemi, alcune persone debbano crearsene comunque, per amor del
sadomasochismo. C'è un paragrafo dell'ultima pubblicazione di Bjarne Stroustrup
che parla delle "Eccezioni che non sono errori", ovvero dell'utilizzo delle
eccezioni per scopi diversi dal trattamento degli errori fatali. Questo mi
sembra il tuo caso.
Ciao
Domenico Barra

sembra il tuo caso.
Oh yeah. A me personalmente piace di più il const int *, però quasi quasi
provo con tutti e due i sistemi per vedere come impattano le eccezioni sulle
prestazioni.
Grazie ancora!
Lanugo

Ricapitolando, quando hai tre alternative, due delle quali le avete gia'
discusse:
- Lanciare un'eccezione, che e' probabilmente il metodo piu' elegante,
  ma ti apre tutta una serie di problemi.
- Restituire un puntatore in modo da usare il puntatore nullo per
  indicare assenza di valore. In questo modo pero' lasci in giro
  puntatori all'interno di una struttura che potrebbe venir distrutta
  quando i puntatori sono ancora attivi.
- Identificare un valore convenzionale per indicare "valore
inesistente".
  Ad esempio potresti usare il massimo intero rappresentabile. Poi 
  dovresti pero' verificare di non ottenere mai tale valore 
  inavvertitamente.
Come vedi ciascuna alternativa ha dei difetti: sta a te scegliere quella
piu' adatta ai tuoi scopi.
Ciao,
Nicola

esistente.
attento che i consigli non sono da prendere come leggi. Probabilmente
ti hanno consigliato questo per rendere piů pulito il tuo codice: ma
nel tuo caso l'uso di una eccezione migliorerebbe molto lo stile, piů
di quanto se usassi altre tecniche. Tanto piů che se ho capito bene ti
troveresti a scrivere una cosa del genere, con lo svantaggio di dover
deferenziare il puntatore (cosa non tanto comprensibile, almeno in un
primo momento):
if (get_el()==NULL) 
	// codice
else
	// altro codice
questa scrittura č logicamente equivalente ma molto piů pulita:
try { 
	get_el();
	// codice
}
catch( Null ) {
	// altro codice
}
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.44, higher than 97% of all previous test takers.
Visual Basic 5: 3.06, higher than 77% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

esistente.
Devo dirti che anch'io in un caso come questo avrei seri dubbi sull'
effettiva utilita dell'uso di eccezioni, ma é anche altrettanto vero
che le alternative non sono un granché. Usare un valore di riferimento
per segnalare la non presenza di un elemento nell'array mi sembra un
sistema piuttosto squallido ( ed anche molto pericoloso), usare un
parametro alternativo di tipo bool mi sembra solo squallido(ma
efficace), restituire un puntatore e controllare che non sia nullo mi
sembra anch'esso un metodo un pò troppo macchinoso, ma é sicuramente
meglio delle due precedenti soluzioni.
Il Ghenio
-----
James: Adesso so finalmente cosa provano i panni messi in lavatrice!
Jesse: Avremo bisogno di un candeggio!!
(Team Rocket)
-----

 
ma perché non ritornare un reference, magari const?
certo questo richiederebbe di dover lanciare una eccezione se il dato 
richiesto non esiste. Ma nella classe si potrebbe anche fornire un metodo 
che indichi se un valore per una certa coordinata esiste o meno, oppure 
due metodi che ritornino le dimensioni dell'array. Se l'utilizzatore 
della tua classe sarà previdente, controllerà prima se il valore che sta 
per chiedere esiste, evitando quindi di chiamare il metodo che lancerebbe 
l'eccezione. 

l'eccezione.
Già, ma l'utilizzatore (che sarei io stesso :-) tende ad essere dannatamente
poco previdente...
Lanugo

elemento che non esiste si potrebbe beccare un access violation.
Interessantissimo, non lo sapevo.
Giusto per curiosità, cosa capita se accedo con [] out of range? torna roba
a casaccio come presuppongo, con il rischio di andare a leggere cose che non
si dovrebbero potere leggere (= violazione di segmento o roba del genere?).
Grazie,
Lanugo

 si dovrebbero potere leggere (= violazione di segmento o roba del genere?).
L'operator [] e' definito come opzionale per le sequenze. Le due sequenze della
libreria che lo supportano sono vector e deque. Se S e' la classe della sequenza
e s e' una sua istanza e n un intero s[n] corrisponde a *(s.begin()+n). Dato che
s.begin() ritorna un S::iterator che e' implementation defined, quello che
capita dipende dalla tua implementazione.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

, 
lan...@SCEMOCHISPAMMAflashmail.com says...

la risposta di Andrea Ferro è corretta.
se ne volevi una più sintetica, in soldoni, ti può capitare che:
sicuramente non leggi un valore corretto
probabilmente mandi anche in crash l'applicazione
... varie altre disgrazie 
come giustamente supponevi...

 ha scritto nel messaggio
news:3A89356D...@divalsim.it...

Personalmente sconsiglierei l'uso delle eccezioni.
Una soluzione alternativa potrebbe essere:
class int_ref     // meglio un template
{
    private:
        int* p;
    public:
        int_ref(int* x)
        : p(x) {  }
        operator bool() const { return p == 0; }
        int operator*() const { return *p; }
};
Semplicemente incapsula il modo di procedere in C.
Saluti   Manlio Perillo