2010-01-05 14 views
7

È sicuro memcopy myvect.size() * sizeof (foo) byte dal memoryadress del primo elemento di unC++ std :: coppia, std :: vector e memcopy

std::vector<std::pair<T1, T2> > myvect 

in un array di

struct foo{ 
    T1 first; 
    T2 second; 
} 

se l'array è allocato con lo stesso numero di elementi delle dimensioni del vettore?

grazie

+1

std :: coppia è una struct, lo standard dice il compilatore determina il layout se l'ordine deve essere mantenuto, per cui nel caso di std :: coppia il tuo compilatore può decidere di posizionare il padding di 3 byte dopo ogni char per l'allineamento ottimale, quindi no non puoi assumere layout di memoria contiguo - fine della storia. –

risposta

8

No, una classe contenente T1 e T2 non è garantito lo stesso layout o allineamento std::pair<T1, T2>, almeno in C++ 98 (poiché std::pair non è un tipo POD). La storia potrebbe essere diversa in C++ 0x.

+0

ma std :: pair è solo un POD perché ha un costruttore definito dall'utente, no? e questo non dovrebbe cambiare qualcosa sul layout della memoria - o lo fa? – Mat

+0

In C++ 98, le implementazioni possono utilizzare un layout diverso per i tipi non POD rispetto ai tipi POD. In C++ 0x, se ricordo bene, c'è una designazione speciale per i tipi che hanno costruttori, ma non hanno classi base, funzioni virtuali o membri non banali. Non riesco a ricordare il suo nome, ma l'idea è che tali tipi siano abbastanza semplici da essere "memcpyabili". –

+1

@Chris: layout standard, ma una classe con layout standard non è * necessariamente * sicura per la copia, significa solo (in effetti) che il compilatore non ha inserito brutte sorprese. Una classe RAII contenente un puntatore a un oggetto assegnato all'heap, che libera sulla distruzione e sui cloni sull'assegnazione, è un layout standard ma non POD e probabilmente non dovrebbe essere copiata con memcpy. –

0

In generale, n. Su alcune piattaforme/compilatori/implementazioni STL potrebbe essere, ma non farlo comunque. Dovresti fare affidamento sui dettagli di implementazione di entrambe le coppie <> e vettore <>.

Io stesso ho commesso il peccato di fare affidamento sul vettore <> come array contiguo. Per questo, mi pento profondamente. Ma la coppia <> ... Basta dire di no.

+5

In realtà il vettore <> è garantito come un array contiguo. –

+0

@Fred: citare per favore? –

+0

È praticamente accettato che 'std :: vector ' sia contiguo (penso che le future versioni di C++ lo specificheranno), e che '& vec [0]' dovrebbe essere utilizzabile come una matrice di dimensione 'vec.size()' . Ma fare 'memcpy' su tipi non POD come' std :: pair' è rischioso, sì. –

4

La risposta alla domanda non ha chiesto è probabilmente std::transform:

struct pairToFoo { 
    // optionally this can be a function template. 
    // template<typename T1, typename T2> 
    foo operator()(const std::pair<T1,T2> &p) const { 
     foo f = {p.first, p.second}; 
     return f; 
    } 
}; 

std::transform(myvect.begin(), myvect.end(), myarray, pairToFoo()); 

O std::copy, ma dare un pippo operator= prendendo una coppia come parametro. Questo presuppone che si può riscrivere foo, però:

struct foo { 
    T1 first; 
    T2 second; 
    foo &operator=(const std::pair<T1,T2> &p) { 
     first = p.first; 
     second = p.second; 
     return *this; 
    } 
}; 

std::copy(myvect.begin(), myvect.end(), myarray); 
+0

'std :: transform()' è qualcosa che non ricordo mai. Mai. Forse ora che l'ho detto pubblicamente, a volte mi viene in mente. –

+1

'std :: transform' è ciò che ottieni invece di map e zipWith. Quindi, se ogni volta che dimentichi la trasformazione, riscrivi la funzione pertinente in Haskell, poi te ne ricorderai. Se solo per evitare di dover scrivere Haskell. –