Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    [C++] Funzioni che restituiscono vettori

    È possibile realizzare in C++ funzioni che restituiscono array? Ho provato così, ma il compilatore mi da errore.

    codice:
    double [] scalarProduct(const double a[], const double b[], int dim)
    {
    	double c[dim];
    	
    	for (int i=0; i<dim; i++)
    	{
    		c[i]=a[i]*b[i];
    	}
    	
    	return c;
    }

  2. #2
    A parte il fatto che in quella funzione stai dichiarando un array sullo stack di dimensioni non note a compile time (il che non è consentito dallo standard C++), se non ricordo male non esiste il passaggio per valore degli array C-style, per cui di fatto stai restituendo un puntatore ad una variabile locale. Questo non va bene per niente, dato che essa viene distrutta quando la funzione ritorna.
    Il modo "classico" di gestire la questione è allocare l'array da restituire con new (che fornisce memoria che va deallocata esplicitamente) e restituire tale puntatore:
    codice:
    double * scalarProduct(const double a[], const double b[], int dim)
    {
    	double * c=new double[dim];
    	for (int i=0; i<dim; i++)
    		c[i]=a[i]*b[i];
    	return c;
    }
    Tuttavia, il chiamante deve ricordarsi di deallocare la memoria, e in ogni caso restituire un puntatore in questa maniera non è buona norma, dato che non risulta immediatamente chiaro di chi sia la responsabilità di liberare la memoria (in particolare, se ricada sul chiamante o meno).
    Per questo motivo, sono nati gli smart pointers: classi che incapsulano un puntatore, distruggendo l'oggetto a cui punta quando esse vengono distrutte, e che, a seconda dell'implementazione, forniscono una semantica di trasferimento o di condivisione della responsabilità di deallocare l'oggetto puntato (i più semplici poi negano in blocco la copia, per cui il puntatore nasce e muore con l'oggetto-smart pointer).
    A questo proposito, nell'attuale standard C++ viene fornito std::auto_ptr, che fornisce una semantica di trasferimento della proprietà del puntatore: ossia, ogni oggetto auto_ptr costruito da un altro del medesimo tipo ottiene la responsabilità per la distruzione dell'oggetto puntato. Questo consente di fare una cose del genere:
    codice:
    std::auto_ptr<UnOggetto> UnaFunzione()
    {
        std::auto_ptr<UnOggetto> ret(new UnOggetto);
        // ...
        return ret;
        // qui ret viene distrutto, ma non viene deallocato ciò a cui punta poiché la proprietà del puntatore
        // è già stata trasferita al valore restituito
    }
    
    // ...
    {
        std::auto_ptr<UnOggetto> a = UnaFunzione();
        // ...
    } // a viene distrutto, poiché non ne sono state fatte copie anche l'oggetto a cui punta viene deallocato automaticamente
    Tuttavia, std::auto_ptr non è previsto per gli array, e pertanto non si può usare con essi (ciò dipende dal fatto che per deallocare un array si usa delete[] mentre auto_ptr internamente usa il normale delete).
    In ogni caso, il nuovo standard C++ fornisce unique_ptr, che funziona in maniera analoga ad auto_ptr (ma usando la nuova move semantic) e supporta gli array. Ulteriori smart pointers sono disponibili nella relativa liberia di boost).

    In ogni caso, per gli array in genere gli smart pointers sono di utilità limitata, dal momento che la STL già fornisce di suo un ottimo container con prestazioni analoghe ai normali array allocati sull'heap, ossia std::vector, che per fortuna gestiscono internamente tutte le menate di gestione della memoria:
    codice:
    std::vector<double> scalarProduct(const double a[], const double b[], size_t dim)
    {
    	std::vector<double> c(dim);
    	for (size_t i=0; i<dim; i++)
    		c[i]=a[i]*b[i];
    	return c;
    }
    D'altra parte, se preferisci un array allocato sullo stack (naturalmente di dimensioni note al momento della compilazione) per ragioni di performance, il nuovo standard fornirà std::array:
    codice:
    template <unsigned int Dim>
    std::array<double,Dim> scalarProduct(const double a[], const double b[])
    {
    	std::array<double,Dim>;
    	for (size_t i=0; i<dim; i++)
    		c[i]=a[i]*b[i];
    	return c;
    }
    Infine, c'è la soluzione più semplice di tutte: senza scomodare librerie o container vari, basta passare l'array di destinazione come parametro non-const:
    codice:
    void scalarProduct(double out[], const double a[], const double b[], int dim)
    {
    	for (int i=0; i<dim; i++)
    		out[i]=a[i]*b[i];
    }
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    In effetti l'ultima soluzione è quella che abbiamo visto a lezione, però, dato che io provengo dal Java, mi chiedevo se fosse possibile anche in C++ realizzare una funzione che restituisca una array come ho postato sopra.

    Grazie mille per la risposta. Sei stato molto esauriente.

  4. #4
    Amaro C++, il gusto pieno dell'undefined behavior.

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.