Newsgroup: it.comp.lang.c++
Titolo: info su standard : sono ammessi puntatori a reference ?

Come da oggetto, è legale e/o può avere qualche senso voler 
dichiarare un puntatore a una reference ? qualcosa tipo :
int & * A;
non riesco a immaginare che differenza potrebbe avere una simile 
variabile A rispetto ad un "plain" int *, né in quale contesto 
potrebbe tornare utile (ammesso che sia legale).
Mi sembra che anche dereferenziando un normale "puntatore a 
intero" (per es.), benché il tipo formale dell'espressione sia 
"intero", di fatto si tratti comunque di un riferimento a 
memoria allocata altrove, e in questo senso in effetti la 
dichiarazione su cui chiedo lumi sembra inutilmente ridondante.
Ma lo sarebbe in qualsiasi contesto ?
ciao & grazie in anticipo
Soviet
P.S. VCPP6 mi insulta dicendo che è illegale, aggiungendo un 
commento che non mi è del tutto chiaro
'initializing' : cannot convert from 'int *' to 'int ** '
         Types pointed to are unrelated; conversion requires 
reinterpret_cast, C-style cast or function-style cast
dal quale presumo che cerchi di interpretare
int & *  come  int * *
(nel qual caso un puntatore a reference viene visto come 
concettualmente diverso dal plain int * che penserei logico
P.P.S. il dubbio è astratto, non connesso con effettiva esigenza 
concreta.

No, almeno da quel che ricordo:
Ci sono alcune restrizioni per l'uso dei reference.
Non può esserci un reference a una variabile reference.
Non è possibile creare un array di reference.
Non si può creare un puntatore ad un reference. Quindi non puoi
applicare l'operatore & a un reference.
I reference non sono consentiti per i campi di bit.
Un reference è un alias e dev'essere inizializzato usando un oggetto
dello stesso tipo come il reference.
Se il reference è const può essere inizializzato da un oggetto di tipo
differente o un rvalue.
Ciao.

 applicare l'operatore & a un reference.
Questo anche:
int main(int,char**) {
   int a=3;
   int&b=a;
   int*c=&b;
}
Sono estensioni allo standard???
  bye
	av.

 }
Ma non
	int &*a;

 reinterpret_cast, C-style cast or function-style cast
gcc piu' semplicemente dice "error: cannot declare pointer to `int&'".
Se la memoria non mi inganna, ma non ho controllato, mi sembra che lo 
standard non faccia alcuna richiesta in merito all'implementazione dei 
reference. Normalmente in memoria sono come dei puntatori (dai quali 
differiscono quasi solo per la sintassi), ma potrebbero anche non 
esistere proprio a livello "fisico". In quest'ultimo caso, non sarebbe 
possibile per un puntatore riferirsi ad essi.
Sperando di non aver detto fesserie...
  bye
	av.

 int & * A;
Se fosse valido potresti scrivere:
int & * A;
void fun(int &x) {
	A=&x;
}
void print() {
	cout<<*A<<endl;
}
void g() {
   int u;
   u=2;
   fun(u);
}
main() {
   g();
   print();
}
ma questo codice è insensato, perché dopo aver eseguito g() la variabile 
u non esiste più, mentre il puntatore A esiste ancora...
E.

 	av.
No. Le ho lette su un libro di un mio amico.
Esattamente a pg 166 di Guida al C++ di Herbert Shildt.
Se poi questo non corrisponde al vero.. chiedo scusa e suggerisco al
mio amico
di cambiare manuale.
Ciao.

?manu* ha scritto:

Beh, ma qui basta sostituire "int*A" a "int&*A" perche' compili, pur 
restando "undefined behaviour".
  bye
	av.

Andrea ha scritto:

Forse e' solo questione di capirsi.
Io l'avevo intesa nel modo in cui ho scritto gli esempi, in tal caso e' 
falso.
?manu* pero' l'ha intesa in modo diverso...
  bye
	av.

 	av.
Non preoccuparti, nessuna polemica.
Ho copiato quanto scritto dal libro appunto per non dire "cavolate".
Non ho sottomano lo standard, ma purtroppo per qualche giorno ho solo
questo libro.
I tuoi esempi sono corretti.
Probabilmente credo sia da intendere come dice ?manu*.
Ciao.

 Ciao.

 E.

 questo libro.
Schildt è noto per la sua ottima prosa e la scarsissima comprensione per
l'argomento di cui scrive. Poi in particolare se c'è necessità apro lo
standard e vi dico (è tardi e io ho un baco da prendere :P )
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.


wrote:

No. Dal momento che b e' automaticamente dereferenziata le
inizializzazioni di c nei due esempi corrispondono in tutto e per
tutto rispettivamente a
int&c=a;
e
int*c=&a;
Le cose che piu' si avvicinano alla copia di reference sono il
passaggio per reference ed il ritorno per reference:
int & f(int & i) { return i; }
int & g(int & i) { return i; }
int main() {
  int a = 5;
  int & b = f(g(a));
}
Ora non ho tempo, ma ti consiglio di provare a generare il listato
assembler con un compilatore che lo supporta. Ricordati di
disabilitare le ottimizzazioni!
Ciao,
Nicola
Ciao,
Nicola

 termini.
Temo che pensare ad una reference come ad un puntatore non sia la cosa 
giusta. Le ulteriori limitazioni che vengono messe alle reference, sono 
importanti. Meglio pensare alle reference come ad "alias", nomi diversi 
di uno stesso oggetto. Inoltre queste limitazioni sono un aiuto per il 
compilatore, che può fare maggiori assunzioni.
E.

 restando "undefined behaviour".
Sì è vero... Diciamo che con i puntatori è risaputo che puoi fare 
casini. Con i reference dovrebbe essere più difficile.
Mi immagino che un programma scritto senza usare i puntatori (ma solo 
valori e reference) non dovrebbe poter dare "segmentation fault"...
Ok, mi immagino che non sia vero. Almeno bisogna eliminare anche gran 
parte delle conversioni di tipo... e che altro? Rimane qualcosa?
E.

 puntatori.
Sì, è questa anche la mia interpretazione. Una reference deve essere 
sempre valida. Niente NULL, per esempio.
E.

 parte delle conversioni di tipo... e che altro? Rimane qualcosa?
% ./segfault    
[1]    23098 segmentation fault  ./segfault
% cat segfault.c
int f() {
        return f();
}
int main() {
        f();


 }
Sì... vabbè... ok!
Una curiosità... pensavo che i compilatori più seri ottimizzassero 
questo tipo di chiamate ricorsive in modo da fare un jump, senza 
incrementare lo stack pointer. In tal caso questo codice andrebbe in 
loop senza dare segfault. Ma ovviamente in situazioni più complesse 
questo problema è inevitabile.
E.

 questo tipo di chiamate ricorsive in modo da fare un jump
il vc8 una funzione del genere la ottimizza in un jump su se stesso, 
oltre a darti un comodo warning di "exit condition missing" o qualcosa 
del genere. a memoria dovrebbe fare lo stesso anche su due funzioni f() e 
g() mutualmente ricorsive tipo:
void g() ;
void f() { g() ; }
void g() { f() ; }

 g() mutualmente ricorsive tipo:
Sì, in effetti quando si ha una situazione del tipo
... f(...) {
	....
	return g(...)
}
il return può essere compilato come un semplice jump se f e g ritornano 
lo stesso tipo e se hanno la stessa dimensione per gli argomenti. La 
funzione che ha chiamato f toglierà dallo stack gli argomenti di g 
pensando che siano quelli di f e prendera il valore di ritorno di g 
pensando che sia quello di f. Non dovrebbe essere difficile per un 
compilatore identificare questa situazione...
E.
E.

 questo problema è inevitabile.
Mah, questa è una possibile ottimizzazione (che ha pure un nome fancy,
eh :) ). Mi spiego, un compilatore *può* farla, ma non necessariamente
deve. BTW, scheme *impone* che se è possibile farla va fatta.
In ogni caso è possibile scrivere funzioni in cui non sia possible fare
tail recursion optimization. Anzi, spesso viene naturale scriverle in
tale modo. Non a caso i libri che trattano di programmazione
dichiarativa (logica o funzionale) generalmente usano un capitolo
proprio per mostrare come trasformare il codice ricorsivo in codice
iterativo (dove nel loro jargon si intende che la ricorsione è
ricorsione in coda, che fa si che si abbia un uso 'iterativo' del call
stack).
Tipicamente prendiamo il fattoriale scritto in modo naive e seghiamo la
condizione di uscita.
int fatt(int n) {
  return n * fatt(n-1);
}
Ecco, questa andrà certamente in seg fault. Lo stack non può essere
riutilizzato perchè n ci va tenuto sopra poichè può essere usato e
buttato solo dopo avere calcolato fatt(n-1).
Ovviamente il classico sistema di ottimizzazione (sta volta mettiamo
anche la condizione di uscita :P) 
int fatt(int n) {
   assert(n>=0);
   return fatt_aux(n, 1);
}
int fatt_aux(int n, int acc) {
   if (n <= 1)
        return acc;
   else
       return fatt_aux(n-1, acc*n);
}
Beware of bugs in the above code; I have only proved it correct, not
tried it. <cit>
