Visualizzazione dei risultati da 1 a 3 su 3
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2006
    Messaggi
    46

    [C++] Ambiguità delle chiamate per riferimento

    Ciao a tutti, vengo subito al sodo:

    Nono sono un programmatore ma non so per quale masochistico motivo ho studiato bene il C. Per non so quale altra masochistica ragione ora mi sto avvicinando al C++, però non mi è chiara l'effettiva utilità di alcune delle "innovazioni" di questo linguaggio. Fra tutte quella che mi ha lasciato più perplesso è questa chiamata per riferimento. In C io scrivevo:

    codice:
    void swap(int * x, int * y) {
    
        int temp;
        temp=*y;
        *y=*x;
        *x=temp;
    }
    
    int main(int argc, char **argv) {
    
        int x;
        int y;
        swap(&x, &y);
    }
    Questo tipo di notazione è abbastanza chiaro: quando richiamo la funzione swap(int*, int*) nel main inserisco gli indirizzi dei due interi che voglio che vengano scambiati. Anche senza conoscere la funzione swap(int*,int*), il fatto di aver passato alla funzione degli indirizzi di memoria mi suggerisce che le variabili x, e y potranno essere manipolate dalla funzione, se invece la la chiamata fosse stata swap(x,y) sarei stato sicuro che le variabili x e y sarebbero rimaste invariate. In C++ invece è tutto diverso, poiché il codice di prima si può scrivere anche:

    codice:
    void swap(int  &x, int  &y) {
    
        int temp;
        temp=y;
        y=x;
        x=temp;
    }
    
    int main(int argc, char **argv) {
    
        int x;
        int y;
        swap(x, y);
    }
    Probabilmente sono io che non ho la mente abbastanza aperta, ma questo tipo di notazione mi pare parecchio ambigua. Non solo nella chiamata swap(x,y), non ho idea che in realtà sto passando degli indirizzi di memoria, ma nella funzione swap(int &, int &) le variabili x, e y vengono trattate come se fossero interi e non puntatori, rendendo il tutto meno immediato da comprendere, almeno per me. Eppure credo che lo scopo di tutto questo sia semplificare la lettura dei programmi.
    Ho letto parecchi programmi in C++ e raramente ho visto programmatori adottare questo tipo di notazione.

    Sono io che sono ignorante o effettivamente la 'vecchia maniera' era meglio? Se mi sbaglio potete farmi degli esempi in cui questo nuovo modo di scrivere aumenta la chiarezza di un programma? Scusate per la lunghezza del post

  2. #2
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Beh io credo che in C++ siano stati introdotti i riferimenti proprio per facilitare la gestione dei passaggi per riferimento degli argomenti ad una funzione... in effetti può non essere immediato entrare nell'ordine di idee che anteponendo una & ai nomi dei parametri nel prototipo di una funzione, questi poi sono dei puntatori, ma una volta fattaci l'abitudine può diventare relativamente più semplice leggere e scrivere il codice.

    Sono io che sono ignorante o effettivamente la 'vecchia maniera' era meglio? Se mi sbaglio potete farmi degli esempi in cui questo nuovo modo di scrivere aumenta la chiarezza di un programma?
    Se vuoi un esempio di come questo possa essere di aiuto in alcuni casi, considera questo codice che è un'implementazione (non mia! Anzi scusa se è un po' disordinata) dell'algoritmo LCS

    codice:
    #include <iostream>
    #include <string>
    using namespace std;
    string Lcs(string X, string Y, int **C, char **B)
    {
    	int X_len=X.length()+1; int Y_len=Y.length()+1;
    	int i,j;
    	string lcs=" ";
    	C=new int*[X_len];
    	B=new char*[X_len];
    	for(i=0; i<X_len; i++)
    	{
    		C[i]=new int[Y_len];
    		B[i]=new char[Y_len];
    	}
    	B[0][0]='\\';
    	for(i=1; i<X_len; i++)
    	{
    		for(j=1; j<Y_len; j++)
    		{
    			if(X[i-1]==Y[j-1])
    			{C[i][j] = 1 + C[i-1][j-1];  B[i][j] = '\\';}
                else if(C[i-1][j] >= C[i][j-1])
    		                  { C[i][j] = C[i-1][j]; B[i][j] = '|';}
    		          else {C[i][j]=C[i][j-1]; B[i][j] = '-';}
    		}
    	         }
    for(i = 1; i< Y_len; i++)                  // Costruisce la stringa di lunghezza LCS
    	{ if(C[X_len-1][i] > C[X_len-1][i-1])  lcs = lcs + Y[i-1];}
    	return lcs;
    }
    int main(){
    	string X = "FRANCESCO"; string Y = "FWANCICO";
            int X_len = X.length() + 1; int Y_len = Y.length() + 1; int i,j;
    	int **C=NULL; char **B=NULL;
    	string lcs = Lcs(X,Y,C,B);
    //        cout << "LCS = " << C[X_len-1][Y_len-1] << lcs <<endl<< endl << "   ";
             // Stampa la matrice C che contiene le soluzioni dei vari sottoproblemi
    	for(i = 0; i< Y_len;i++)   cout << " " << Y[i];
    	for (i =0; i< X_len; i++){
    		cout << endl;
    		if (i >= 1)    cout << X[i-1] << " ";
    		else            cout << "  ";
    		for (j = 0; j< Y_len; j++)   {  cout << C[i][j] << " "; }
    	}
    	cout << endl << endl << "   ";     
     // Stampa la matrice B che contiene i percorsi  dei vari sottoproblemi	
    	for(i = 0; i< Y_len; i++)     cout << " " << Y[i];
    	for (i =0; i< X_len; i++){
    	cout << endl;
    	   if (i >= 1)    cout << X[i-1] << " ";
    	    else           cout << "  ";
    		for (j = 0; j< Y_len; j++) {cout << B[i][j] << " ";}
    	}
    	cout << endl;
       if (C != NULL)  // Delloca le matrici
    	{
    	 for (i=0;i<X.length();i++)  { delete C[i]; delete B[i];}
    	delete C; delete B;
    	}
    
    	return 0;
    }
    al di là di quello che l'algoritmo deve fare, come puoi vedere nel main() viene allocato spazio per due matrici che poi vengono passate alla funzione Lcs che dovrà lavorarci sopra. Ora, scritto in questo modo, il programma non funziona perché le matrici sono passata per valore alla funzione, non per riferimento... quindi le modifiche che apporta la funzione alle matrici sono locali ad essa e non visibili in main().

    Come risolvere? Dovremmo passare le matrici per riferimento, quindi dichiarare passare un puntatore a queste... ma C e B sono già puntatori a puntatori, quindi dovremmo ricorrere a puntatori a puntatori a puntatori... ^^ (ovviamente si potrebbe anche semplificare il tutto rappresentando le matrici con un puntatore singolo e ricorrendo poi alla mappa di memorizzazione ma vabbè...)

    Ecco che invece basterà semplicemente sostituire l'intestazione della funzione con

    codice:
    string Lcs(string X, string Y, int **&C, char **&B)
    senza apportare modifiche al suo corpo, e il programma funziona correttamente.
    every day above ground is a good one

  3. #3
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Yuvevon
    Beh io credo che in C++ siano stati introdotti i riferimenti proprio per facilitare la gestione dei passaggi per riferimento degli argomenti ad una funzione...
    In realtà sono stati introdotti per l'overloading degli operatori perché farlo con i puntatori sarebbe stato scomodo.

    giampa
    Ho letto parecchi programmi in C++ e raramente ho visto programmatori adottare questo tipo di notazione.
    Sono io che sono ignorante o effettivamente la 'vecchia maniera' era meglio?
    Non so che programmi tu abbia visto ma i reference sono molto usati.
    Il motivo principale è che un puntatore può essere dichiarato e inizializzato in un secondo momento, mentre un reference pretende di essere inizializzato al momento della dichiarazione.
    Inoltre i puntatori possono essere scambiati, i reference no. Sono legati a vita al loro riferimento.

    Che sia meglio o peggio giudica tu.
    codice:
    void swap(int * x, int * y) {
        int temp;
        temp=*y;
        *y=*x;
        *x=temp;
    }
    
    int main(int argc, char **argv) {
        int x;
        int y;
        swap(&x, 0);
    }
    Codice perfettamente legale ma che produce un crash.
    (E non tirare in ballo l'attenzione del programmatore. Di puntatori dimenticati ne è pieno il mondo )
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.