2010-09-08 4 views
5

Sto lavorando con una funzione che restituisce alcuni dati come std::vector<char> e un'altra funzione (si pensi alle API legacy) che elabora i dati e prende uno const char *, size_t len. C'è un modo per staccare i dati dal vettore in modo che il vettore possa uscire dall'ambito prima di chiamare la funzione di elaborazione senza copiando i dati contenuti nel vettore (è ciò che intendo implicare con scollegando).Posso staccare un std :: vector <char> dai dati che contiene?

Alcuni codice di schizzo per illustrare lo scenario:

// Generates data 
std::vector<char> generateSomeData(); 

// Legacy API function which consumes data 
void processData(const char *buf, size_t len); 

void f() { 
    char *buf = 0; 
    size_t len = 0; 
    { 
     std::vector<char> data = generateSomeData(); 
     buf = &data[0]; 
     len = data.size(); 
    } 

    // How can I ensure that 'buf' points to valid data at this point, so that the following 
    // line is okay, without copying the data? 
    processData(buf, len); 
} 
+2

Perché non solo mantenere il 'data' vettore nell'ambito funzione e la chiamano' processData (e dei dati [0], data.size()) ' ?? –

+0

@David Rodríguez - dribeas: In * this code sketch *, l'ambito di 'processData()' è l'antenato diretto dell'ambito di 'data'. Tuttavia, nelle basi di codice del mondo reale, potrebbero esserci dozzine di frame di stack tra i due ambiti. Oppure immagina se 'processData' pubblicherebbe il puntatore e la lunghezza del buffer specificato su un altro thread e poi ritornerà immediatamente - devi assicurarti che i dati rimangano validi fino a quando il thread del consumatore non lo ha elaborato. Questi sono solo due esempi in cui potresti voler disaccoppiare la durata di un contenitore dalla durata dei dati contenuti. –

+0

Abbastanza divertente la risposta che hai accettato è esattamente quello che ho indicato nel commento precedente, reso ancora più complesso ... invece di usare un vettore locale e scambiare con il globale, basta usare il globale ... Ora, questo è diverso da cosa stai dicendo ora. Il trasferimento di proprietà e la gestione della durata sono gestiti meglio con indicatori (intelligenti): basta tenere il contenitore attraverso un puntatore e passare la proprietà intorno ... –

risposta

14
void f() { 
    char *buf = 0; 
    size_t len = 0; 
    std::vector<char> mybuffer; // exists if and only if there are buf and len exist 
    { 
     std::vector<char> data = generateSomeData(); 
     mybuffer.swap(data); // swap without copy 
     buf = &mybuffer[0]; 
     len = mybuffer.size(); 
    } 

    // How can I ensure that 'buf' points to valid data at this point, so that the following 
    // line is okay, without copying the data? 
    processData(buf, len); 
} 
+0

Funziona alla grande! Grazie - non mi sono reso conto che esiste una funzione membro swap() sui vettori. –

+0

Sì, è così che si fa con 'std :: vector'. – sharptooth

+2

@Frerich: i contenitori STL generalmente dispongono di un membro 'swap' o una funzione libera' swap'. Non è un requisito, è solo un buon design. –

-5

io non lo consiglio, ma:

char* ptr = NULL; 
int len = -1; 
{ 
    vector<char> vec; 
    /* ... fill vec with data ... */ 
    vec.push_back(NULL); // dont forget to null terminate =) 
    ptr = &vec.front(); 
    len = vec.size(); 
    // here goes... 
    memset((void*)&vec, 0, sizeof(vec)); 
} 
// vec is out of scoop, but you can still access it's old content via ptr. 
char firstVal = ptr[0]; 
char lastVal = ptr[len-1]; 
delete [] ptr; // don't forget to free 

Voila!

Questo codice è in realtà abbastanza sicuro poiché il distruttore di VEC chiamerà delete [] 0;, operazione sicura (a meno che non si abbia qualche strana implementazione di stl).

+5

hai una strana definizione di "sicuro". – jalf

+0

Non sono un avvocato linguistico, ma ci deve essere un comportamento indefinito lì. –

+0

-1. Tutti i compilatori decenti dovrebbero produrre un avvertimento sulla riga 'memset()'. – Dummy00001

3

La soluzione più semplice è nemmeno stato ancora presentato:

void f() { 
    std::vector<char> data = generateSomeData(); 

    processData(&data[0], data.size()); 
} 
+2

-1: questo risponde a una domanda, ma non a quella che ho chiesto; Io ** intenzionalmente ** metto un mirino attorno al vettore 'data' in modo che sia presto fuori dal campo di applicazione per dimostrare il mio punto. –

+0

@Frerich: ma forse risponde a quello che avresti dovuto chiedere. –

+0

@Mike: Sentiti libero di rispondere 'Sotto il grande melo nel giardino', nel caso volessi chiedere 'Dove posso trovare ombra durante i giorni caldi?'. : -} –

Problemi correlati