PDA

View Full Version : [C++] Passaggio di un vector<int>


Manugal
19-05-2007, 17:36
Ciao.

Ho dichiarato in un file, questa classe:


class Dns{
private:
vector<int> proxy;
vector<Provider> provider; //un'array di Provider (Provider è una struct definita in un altro file)
map<string, vector<int> > mapper;
public:
Dns();
Dns(vector<int> , vector<Provider>);
void Associations(int, int);
void stampa_mapper(int []);
};


Il corpo del costruttore con argomenti è:


Dns::Dns(vector<int> newp, vector<Provider> newprov){
proxy=newp;
provider=newprov;
}


Ora se dal main istanzio un oggetto di tipo Dns con tale costruttore, succede che provider viene correttamente copiato da newprov mentre proxy no. Infatti se vado a fare un debugging con gdb mi accorgo che provider contiene correttamente tutti i campi che ho inizializzato nel main, mentre proxy (nonostante sia correttamente inizializzato con tutti i valori nel main) non ha nessun campo inizializzato (anzi l'indirizzo di memoria è proprio NULL). Non capisco perché non riesce a passarglielo correttamente. Avete idee? Grazie.

vizzz
19-05-2007, 19:15
innanzitutto ti consiglio di ottimizzare passando i due vettori al costruttore come puntatore.
ricordo di aver guardato tempo fa il costruttore copia dei vector e non mi sembrava un gran che... secondo me il metodo migliore per caricare i tuoi vettori membri di classe è:

for (unsigned int i = 0; i < newp->size(); i++)
proxy.push_back(newp[i]);

stessa cosa per l'altro vector.
ciao

Manugal
19-05-2007, 20:52
Ah quindi proprio facendo un semplice ciclo. Io perché pensavo che con l'operatore = lo assegnava direttamente (come d'altronde poi ha fatto con vector<Provider>). Strano comunque questo comportamento. Grazie. :)

cionci
19-05-2007, 21:02
Strano...in teoria dovrebbe funzionare...

-fidel-
19-05-2007, 21:04
Ciao.

Ho dichiarato in un file, questa classe:


class Dns{
private:
vector<int> proxy;
vector<Provider> provider; //un'array di Provider (Provider è una struct definita in un altro file)
map<string, vector<int> > mapper;
public:
Dns();
Dns(vector<int> , vector<Provider>);
void Associations(int, int);
void stampa_mapper(int []);
};


Il corpo del costruttore con argomenti è:


Dns::Dns(vector<int> newp, vector<Provider> newprov){
proxy=newp;
provider=newprov;
}


Ora se dal main istanzio un oggetto di tipo Dns con tale costruttore, succede che provider viene correttamente copiato da newprov mentre proxy no. Infatti se vado a fare un debugging con gdb mi accorgo che provider contiene correttamente tutti i campi che ho inizializzato nel main, mentre proxy (nonostante sia correttamente inizializzato con tutti i valori nel main) non ha nessun campo inizializzato (anzi l'indirizzo di memoria è proprio NULL). Non capisco perché non riesce a passarglielo correttamente. Avete idee? Grazie.

A parte le varie ottimizzazioni possibili, come costruisci la classe Dns?
Giusto perchè, se provi questo codice che ho scritto al volo:


#include <iostream>
#include <vector>

using namespace std;

class Test
{
public:
Test(vector<int> v) { vect = v; };
void print() {
for (int i = 0; i < vect.size(); i++)
cout << vect[i] << endl;
}
private:
vector<int> vect;
};

int main()
{
vector<int> v;
Test *test;

v.push_back(1);
v.push_back(3);
v.push_back(5);
test = new Test(v);
test->print();
delete test;

return 0;
}


il tutto funziona.

EDIT: Ricorda una cosa: quando usi l'operatore 'push_back' su un oggetto vector che NON contiene puntatori ma oggetti/tipi, l'oggetto NON viene inserito copiandolo, ma costruendone un altro (quindi viene chiamato il costruttore della classe che stai inserendo). Puoi immaginare i problemi derivanti se usi classi astratte (polimorfismo)... Idem se usi l'operatore =.
Te lo dico perchè vedo dal tuo codice che usi un vector<Provider> (ok che Provider è una struct, ma se un giorno volessi usare una classe, pensando ad un possibile code recycling...).

cionci
20-05-2007, 08:35
Per essere precisi viene usato il costruttore di copia...
Cioè il costruttore (se non è presente è implicito ed utilizza membro a membro sempre il rispettivo costruttore di copia):

TuaClasse(const TuaClasse &)

Quindi nel caso ci siano puntatori a memoria dinamica fra i membri spesso va ridefinito allocando nuova memoria dinamica per la copia creata, che va deallocata poi nel distruttore...

Comunque il problema non credo sia di questo tipo, perché ce l'ha sul primo parametro, cioè quello relativo al vettore di interi, e il problema è strano per questo.

cionci
20-05-2007, 08:37
innanzitutto ti consiglio di ottimizzare passando i due vettori al costruttore come puntatore.
Semmai come riferimento...

Manugal
20-05-2007, 09:25
Infatti quello che volevo fare era passare entrambi i vector per riferimento, solo che per quanto riguarda il vector<int> da questo problema. Provando con un int* non ha problemi invece. :confused:

-fidel-
20-05-2007, 12:05
Per essere precisi viene usato il costruttore di copia...
Cioè il costruttore (se non è presente è implicito ed utilizza membro a membro sempre il rispettivo costruttore di copia):

TuaClasse(const TuaClasse &)

Quindi nel caso ci siano puntatori a memoria dinamica fra i membri spesso va ridefinito allocando nuova memoria dinamica per la copia creata, che va deallocata poi nel distruttore...

Esatto ;)

Comunque il problema non credo sia di questo tipo, perché ce l'ha sul primo parametro, cioè quello relativo al vettore di interi, e il problema è strano per questo.

No infatti, dicevo quella cosa per sua informazione, nel caso volesse usare un vector contenente classi (magari con classi astratte).
Tra l'altro, il codice che ho postato (che fa la stessa cosa che vuole fare lui, che tra l'altro non è il massimo, visto che per lo meno bisogna passare il vector per riferimento, per non sprecare 3 volte memoria) funziona benissimo.

-fidel-
20-05-2007, 12:06
Infatti quello che volevo fare era passare entrambi i vector per riferimento, solo che per quanto riguarda il vector<int> da questo problema. Provando con un int* non ha problemi invece. :confused:

Sì ma comunque è strano: dai un'occhiata al codice che ho postato.

Manugal
20-05-2007, 14:42
Guarda io nel main ho una cosa del genere:


vector<Provider> provider;
...
...
vector<int> proxies;
...
...
for(i=0; i<8; ++i)
proxies[i]=id_proxy;

for(i=0; i<15; ++i){
Provider nuovo;
nuovo.nome_provider="Alice"
nuovo.peso=rand()%100;
nuovo.id_provider=i;
provider.push_back(nuovo);
}

Dns domain_name_server(proxies,provider); //creo l'oggetto così



Avevo provato a leggere tutti gli elementi di proxies[i] nel main e venivano inizializzati come volevo io. Ma una volta che li passo niente. :(

cionci
20-05-2007, 14:49
Prova con proxies.push_back(id_proxy);

Come dicevamo non fare un passaggio per indirizzo, ma fallo per riferimento:

Dns::Dns(vector<int> &newp, vector<Provider> &newprov)

-fidel-
20-05-2007, 16:46
Guarda io nel main ho una cosa del genere:


vector<Provider> provider;
...
...
vector<int> proxies;
...
...
for(i=0; i<8; ++i)
proxies[i]=id_proxy;

for(i=0; i<15; ++i){
Provider nuovo;
nuovo.nome_provider="Alice"
nuovo.peso=rand()%100;
nuovo.id_provider=i;
provider.push_back(nuovo);
}

Dns domain_name_server(proxies,provider); //creo l'oggetto così



Avevo provato a leggere tutti gli elementi di proxies[i] nel main e venivano inizializzati come volevo io. Ma una volta che li passo niente. :(

Devi creare l'oggetto Dns con new...


Dns *domain_name_server = new Dns(proxies, provider);


In più, passa i parametri al costruttore "by reference", altrimenti sprechi 2 volte memoria, come ti ha fatto vedere cionci ;)

cionci
20-05-2007, 16:47
Perchè lo deve creare con new ? :confused:

-fidel-
20-05-2007, 16:52
Attenzione, errore trovato!! :)


for(i=0; i<8; ++i)
proxies[i]=id_proxy;


???
Semmai


for(i=0; i<8; i++)
proxies.push_back(id_proxy);


Se proprio vuoi, puoi continuare a non usare new per creare l'oggetto e farlo implicitamente (io preferisco new e relativa delete, così libero memoria subito, quando non ho più bisogno dell'oggetto).

-fidel-
20-05-2007, 16:54
Perchè lo deve creare con new ? :confused:

Non che sia neccessario per il corretto funzionamento, però, come dicevo prima, hai un maggiore controllo sull'uso della memoria.
Inoltre, non è questo il caso mi pare, però a volte costruire implicitamente l'oggetto mi ha portato strani malfunzionamenti.

Manugal
20-05-2007, 17:09
Aspetta il passaggio è per riferimento, infatti il costruttore ora è definito così:


Dns(vector<int>& , vector<Provider>& );


Quindi chiamando il costruttore in quel modo è passato per riferimento. Per quanto riguarda l'inserimento dei valori anch'io stavo pensando fosse quello che dicevi tu (cioè fare push_back) solo che visto che nel main me lo inzializzava correttamente allora non ci ho neanche provato. Per quanto riguarda l'inizializzazione con new in effetti hai ragione sul fatto che sei più libero nel gestire la memoria, ma a me quelle strutture che creo serviranno per tutto il programma (cioè non ci sono punti intermedi dove potrei disallocarle). In ogni caso credo che userò lo stesso new e delete. ;)

Manugal
20-05-2007, 17:20
Ragazzi ora funziona!!!!! :D

Il problema era proprio il fatto che usavo l'operatore [] invece che push_back. Grazie mille. ;)

-fidel-
20-05-2007, 19:45
Ragazzi ora funziona!!!!! :D

Il problema era proprio il fatto che usavo l'operatore [] invece che push_back. Grazie mille. ;)

;) Il problema sorgeva perché tu assegnavi dei valori ad un vector di dimensione 0 (appena lo crei/definisci contiene 0 elementi, a meno di non specificare qualcosa nel costruttore), quindi assegnando valori con [] semplicemente l'operazione falliva (il programma non si blocca o altro, semplicemente l'operazione viene ignorata dalla classe vector, e viene generato un errore che puoi "catchare").
Invece push_back alloca un nuovo spazio di memoria ed inserisce la variabile.
Non a caso prima 'proxies' era NULL.