Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 16
  1. #1

    [C++] Puntatori a strutture dinamiche | Limitazione template

    Ciao a tutti.

    Sto tentando di creare una classe Vector per rappresentare dei vettori euclidei. Per creare dei vettori a qualsiasi dimensione e di qualsiasi tipo ho deciso di utilizzare dei template e utilizzare un puntatore per tenere traccia degli array o dei vector che contengono le coodrinate (così l'utente ha piena libertà sulla dimensione dei vettori).

    Ora, mentre con gli array non vedo problemi perché sono strutture statiche, mi chiedo se ha senso utilizzate un puntatore a uno std::vector, che può essere riallocato se vengono aggiunti nuovi dati.

    codice:
    // Vector class
    
    #ifndef VECTOR_H
    #define VECTOR_H
    
    #include <vector>
    using std::vector;
    
    template <typename T>
    class Vector
    {
    public:
    	Vector();
    	Vector(const T [], int);
    	Vector(const vector<T>);
    	~Vector();
    	
    private:
    	T* vector_Ptr;
    	int vector_size;
    };
    
    #endif
    codice:
    template <typename T>
    Vector<T>::Vector(const vector<T> array)
    {
    	vector_Ptr = &vector<T>
            vector_size = array.size();
    }
    Inoltre mi chiedevo se è possibile limitare l'istanza di una classe template a tipi fondamentali... Sto vaneggiando?!
    K. L. Thompson
    You can't trust code that you did not totally create yourself.
    A. Bogk
    UNIX is user-friendly, it just chooses its friends.

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381

    Re: [C++] Puntatori a strutture dinamiche | Limitazione template

    Originariamente inviato da RooccoXXI
    Ciao a tutti.
    Ora, mentre con gli array non vedo problemi perché sono strutture statiche, mi chiedo se ha senso utilizzate un puntatore a uno std::vector, che può essere riallocato se vengono aggiunti nuovi dati.
    Concettualmente non fai altro che creare un T** visto che std::vector di suo ha un T* interno. Quindi potrebbe non avere senso.
    Ha più senso invece utilizzare un puntatore T* interno alla tua classe da manipolare come ti serve.

    Inoltre mi chiedevo se è possibile limitare l'istanza di una classe template a tipi fondamentali
    Dipende dal compilatore che usi. Se conforme allo standard C++0x ( g++ > 4.3, Vc++2010), si puo fare una cosa del genere.
    codice:
    template <typename T>
    class Vector { 
        static_assert( std::is_fundamental<T>::value, "Il tipo di dato non è nativo");
    etc...
    Altrimenti sei costretto a specializzare ogni istanza per i tipi fondamentali.

    codice:
    // Vector class
    #ifndef VECTOR_H
    #define VECTOR_H
    
    #include <vector>
    using std::vector;
    
    template <typename T>
    class Vector
    {
    public:
    	Vector();
    	Vector(const T [], int);
    	Vector(const vector[/QUOTE]&<T> );
            Vector& operator=(const Vector& )
     
           // eventuale supporto per la move semantics (solo C++0x)
           Vector& operator=(Vector&& )
           Vector& operator=(Vector&& )
    
    	~Vector();
    	
    private:
    };
    
    #endif 
    
    template <typename T>
    Vector<T>::Vector(const vector<T>& array)
    {
    ...
    }
    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.

  3. #3

    Re: Re: [C++] Puntatori a strutture dinamiche | Limitazione template

    Originariamente inviato da shodan
    Concettualmente non fai altro che creare un T** visto che std::vector di suo ha un T* interno. Quindi potrebbe non avere senso.
    Ha più senso invece utilizzare un puntatore T* interno alla tua classe da manipolare come ti serve.
    Immaginavo che std::vector avesse un puntatore interno (ovviamente!). Però allora se il mio puntatore è inutile (tra l'altro dovrebbe essere vector<T>* e non solo T*, giusto?) come faccio a creare una classe con un solo dato membro (il mio Vettore vero e proprio) che funzioni sia per gli std::vector che per gli array?!

    Dipende dal compilatore che usi. Se conforme allo standard C++0x ( g++ > 4.3, Vc++2010), si puo fare una cosa del genere.
    codice:
    template <typename T>
    class Vector { 
        static_assert( std::is_fundamental<T>::value, "Il tipo di dato non è nativo");
    etc...
    Altrimenti sei costretto a specializzare ogni istanza per i tipi fondamentali.
    Non ho più aggiornato il compilatore. Sono fermo alla 4.2.1. Prossimamente però l'aggiorno ma prima di quest'estate non avrò tempo di aggiornare più di quel tanto le mie conoscenze in C++ (C++0x)!

    Il passaggio per riferimento l'avevo già visto, comunque grazie!
    K. L. Thompson
    You can't trust code that you did not totally create yourself.
    A. Bogk
    UNIX is user-friendly, it just chooses its friends.

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Intanto devi avere due dati: T* e una variabile per la dimensione (int, std::size_t; long long, fai tu).

    Poi basta fare l'overload del costruttore.
    Ad esempio (i tipi delle variabili le semplifico in int per comodità).
    codice:
    // costruttori. 
    Vector(T* p, int size) // costruttore che prende il puntatore al primo elemento e la dimensione.
    {
        _Ptr = new T[Size];
        std::copy(p, p+size,_Ptr);
    }
    
    template <typename InpIter>
    Vector(InpIter first, InpIter last) // costruttore che un input iterator al primo e ultimo elemento.
    {
        _Ptr = new T[ std::distance(first,last) ];
        std::copy(first, last,_Ptr);
    }
    
    T MyArray0[128];
    // etc
    
    Vector vec0(MyArray,128);
    
    T MyArray1[128];
    // etc
    
    Vector vec1(MyArray,MyArray+128);
    // oppure
    // Vector vec1(&MyArray[0],&MyArray[128]);
     
    
    std::vector std_vec;
    // etc
    Vector vec1( vec.begin(),vec.end() );
    Però se devi usare la tua classe solo per memorizzare dati, stai reinventando la ruota.
    Se devi solo travasarli per poi fornire metodi di elaborazione è un altro paio di maniche.

    Tra l'altro la domanda iniziale (sul puntatore a vector) è abbastanza strana. Non ti basta un'istanza al vector, senza per forza averne il puntatore?
    codice:
    template <typename T>
    class Vector
    {
    public:
    // etc	
    private:
    	vector<T> _MyVec;
    };
    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.

  5. #5
    Originariamente inviato da shodan
    Intanto devi avere due dati: T* e una variabile per la dimensione (int, std::size_t; long long, fai tu).

    Poi basta fare l'overload del costruttore.
    Ad esempio (i tipi delle variabili le semplifico in int per comodità).
    codice:
    // costruttori. 
    Vector(T* p, int size) // costruttore che prende il puntatore al primo elemento e la dimensione.
    {
        _Ptr = new T[Size];
        std::copy(p, p+size,_Ptr);
    }
    
    template <typename InpIter>
    Vector(InpIter first, InpIter last) // costruttore che un input iterator al primo e ultimo elemento.
    {
        _Ptr = new T[ std::distance(first,last) ];
        std::copy(first, last,_Ptr);
    }
    
    T MyArray0[128];
    // etc
    
    Vector vec0(MyArray,128);
    
    T MyArray1[128];
    // etc
    
    Vector vec1(MyArray,MyArray+128);
    // oppure
    // Vector vec1(&MyArray[0],&MyArray[128]);
     
    
    std::vector std_vec;
    // etc
    Vector vec1( vec.begin(),vec.end() );
    Però se devi usare la tua classe solo per memorizzare dati, stai reinventando la ruota.
    Se devi solo travasarli per poi fornire metodi di elaborazione è un altro paio di maniche.

    Tra l'altro la domanda iniziale (sul puntatore a vector) è abbastanza strana. Non ti basta un'istanza al vector, senza per forza averne il puntatore?
    codice:
    template <typename T>
    class Vector
    {
    public:
    // etc	
    private:
    	vector<T> _MyVec;
    };
    Ovvio che devo avere anche il dato della dimensione. Comunque non devo reinventare la ruota (anche se sono convinto che sia molto utile per capire veramente come funzionano le cose!), ma voglio creare una classe completa, con ridefinizione degli operatori e tutto per utilizzare dei vettori (intesi come oggetto matematico): somma, moltiplicazione per un numero, prodotto scalare, prodotto vettoriale, ...!

    E da questa classe derivare poi una classe Point.

    Comunque tu consigli allora di utilizzare un vector all'interno della mia classe ed eventualmente se l'utente decide di utilizzare gli array, creare il costruttore in modo che prenda l'array e lo copi nel mio vector?! (Ho capito correttamente ciò che intendevi?!)
    K. L. Thompson
    You can't trust code that you did not totally create yourself.
    A. Bogk
    UNIX is user-friendly, it just chooses its friends.

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da RooccoXXI
    (anche se sono convinto che sia molto utile per capire veramente come funzionano le cose!)
    Questo senz'altro. Anche perché poi ti trovi di fronte a problematiche che magari non avevi neanche previsto.

    Comunque tu consigli allora di utilizzare un vector all'interno della mia classe ed eventualmente se l'utente decide di utilizzare gli array, creare il costruttore in modo che prenda l'array e lo copi nel mio vector?! (Ho capito correttamente ciò che intendevi?!)
    Si. In sostanza la tua classe diventa un wrapper per un vector.
    Alla fine devi solo creare i costruttori sul modello del vector.
    In più non ti devi preoccupare di implementare il costruttore di copia, l'operatore di assegnamento, distruttore e il passaggio a C++0x "potrebbe" risultare indolore.
    In pratica devi solo concentrarti sulle funzioni che intendi sviluppare.
    Riprendendo l'esempio di prima:
    codice:
    #include <vector>
    using std::vector;
    
    template <typename T>
    class Vector
    {
    public:
    	Vector();
    	Vector(const T* ptr, int dim) : _MyVec(ptr, ptr+dim) {}
     
           template <typename InpIter>
    	Vector(InpIter a, InpIter b) : _MyVec(a,b) {}
    
    // funzioni specializzate. 
    	
    private:
            vector<T> _MyVec;
    };
    Tra l'altro ti consiglierei di usare gli iteratori, non l'operatore[] del vector. In questo modo se un giorno vuoi passare da un vector a una deque o list, basta cambiare una linea di codice.
    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.

  7. #7
    Originariamente inviato da shodan
    Questo senz'altro. Anche perché poi ti trovi di fronte a problematiche che magari non avevi neanche previsto.



    Si. In sostanza la tua classe diventa un wrapper per un vector.
    Alla fine devi solo creare i costruttori sul modello del vector.
    In più non ti devi preoccupare di implementare il costruttore di copia, l'operatore di assegnamento, distruttore e il passaggio a C++0x "potrebbe" risultare indolore.
    In pratica devi solo concentrarti sulle funzioni che intendi sviluppare.
    Riprendendo l'esempio di prima:
    codice:
    #include <vector>
    using std::vector;
    
    template <typename T>
    class Vector
    {
    public:
    	Vector();
    	Vector(const T* ptr, int dim) : _MyVec(ptr, ptr+dim) {}
     
           template <typename InpIter>
    	Vector(InpIter a, InpIter b) : _MyVec(a,b) {}
    
    // funzioni specializzate. 
    	
    private:
            vector<T> _MyVec;
    };
    Tra l'altro ti consiglierei di usare gli iteratori, non l'operatore[] del vector. In questo modo se un giorno vuoi passare da un vector a una deque o list, basta cambiare una linea di codice.
    Con gli iteratori faccio ancora un po' di fatica, ma appunto per questo pensavo di utilizzarli! .

    Comunque con l'array devo per forza passare la dimensione? Ero convinto di si ma su questo sito sembrerebbe non obbligatorio.
    C++ Reference

    Infatti utilizza l'operatore sizeof() per ricavare la dimensione dell'array. Questo funziona si a se l'array è passato per riferimento sia se è passato per riferimento di tipo puntatore?
    K. L. Thompson
    You can't trust code that you did not totally create yourself.
    A. Bogk
    UNIX is user-friendly, it just chooses its friends.

  8. #8
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    No. Funziona solo se l'array è definito così:
    codice:
     T my_array[128]; // sizeof(my_array) == 128 * sizeof(T)
    Ma se il tuo array è allocato dinamicamente, o decade in un puntatore perché passato a una funzione:
    codice:
    T* my_array = new T[128]; // sizeof(my_array) == sizeof(void*)
    il giochetto non funziona più.
    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.

  9. #9
    Originariamente inviato da shodan
    No. Funziona solo se l'array è definito così:
    codice:
     T my_array[128]; // sizeof(my_array) == 128 * sizeof(T)
    Ma se il tuo array è allocato dinamicamente, o decade in un puntatore perché passato a una funzione:
    codice:
    T* my_array = new T[128]; // sizeof(my_array) == sizeof(void*)
    il giochetto non funziona più.
    Che significa "decade in un puntatore"?!
    K. L. Thompson
    You can't trust code that you did not totally create yourself.
    A. Bogk
    UNIX is user-friendly, it just chooses its friends.

  10. #10
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Array C e puntatori hanno legami stretti.
    Quando passi un array a una funzione, di fatto passi un puntatore che ha lo stesso nome dell'array.
    codice:
    void funzione(int* p) { 
     // p == arr
    }
    int arr[128];
    
    funzione(arr);
    questo si definisce "decadimento" dell'array in puntatore.
    La notazione:
    codice:
    void funzione(int[] p) { 
     // p == arr
    }
    è solo un alias della prima versione.

    Tuttavia mentre di un puntatore puoi farne quel che vuoi, con l'array non puoi.
    codice:
    void funzione(int* p) { 
     // p == arr
        p++; // ok, punta ad arr[1];
    }
    int arr[128];
    
    funzione(arr);
    // arr++  errore di compilazione!
    int* a = arr;
    a++ // ok, a punta ad arr[1]. Altro decadimento di un array C in un puntatore.
    In pratica il nome dell'array C è un puntatore const che consente di modificare il contenuto, ma non la locazione a cui punta. Per farlo devi effettuare una indirezione tramite un altro puntatore.

    Detto più terra terra, a livello implementativo gli array di per se non esistono: sono puntatori speciali gestiti dal compilatore.
    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 © 2025 vBulletin Solutions, Inc. All rights reserved.