2013-02-06 20 views
12

Non sono riuscito a trovare quella domanda, ed è un problema reale che sto affrontando.Come convertire std :: vector <unsigned char> nel vettore <char> senza copiare?

Ho un'utilità di caricamento file che restituisce std::vector<unsigned char> contenente l'intero contenuto del file. Tuttavia, la funzione di elaborazione richiede una serie contigua di char (e che non può essere modificato - è una funzione di libreria). Poiché la classe che sta utilizzando la funzione di elaborazione memorizza comunque una copia dei dati, desidero archiviarla come vector<char>. Ecco il codice che potrebbe essere un po 'più illustrativo.

std::vector<unsigned char> LoadFile (std::string const& path); 

class Processor { 
    std::vector<char> cache; 
    void _dataOperation(std::vector<char> const& data); 

public: 
    void Process() { 
     if (cache.empty()) 
      // here's the problem! 
      cache = LoadFile("file.txt"); 

     _dataOperation(cache); 
    } 
}; 

Questo codice non viene compilato, perché (ovviamente) non c'è conversione appropriato. Possiamo essere certi, tuttavia, che il vettore temporaneo avrà la stessa quantità di memoria (IOW sizeof(char) == sizeof(unsigned char))

La soluzione ingenua sarebbe quella di iterare sul contenuto di un personaggio temporaneo e castare ogni personaggio. So che in caso normale verrà chiamato il operator= (T&&).

Nella mia situazione è sicuro eseguire la reinterpretazione della conversione, perché sono sicuro che leggerò solo caratteri ASCII. Qualsiasi altro personaggio verrebbe catturato comunque in _dataOperation.

Quindi, la mia domanda è: come convertire correttamente e in modo sicuro il vettore temporaneo in un modo che non comporta alcuna copia?

Se non è possibile, preferirei il modo sicuro di copiare anziché non sicuro. Potrei anche cambiare LoadFile per restituire vector<char> o vector<unsigned char>.

+1

Se si controlla il codice di '_dataOperation', sarà probabilmente più felice nel lungo periodo se lo si fa prendere' vector '. – zwol

+0

@Zack sfortunatamente, io no. È una funzione di libreria. Modificherò la domanda. –

+0

Non esiste un modo _safe_ –

risposta

6

In C++ 11 [basic.lval] p10 dice

Se un programma tenta di accedere al valore memorizzato di un oggetto attraverso un glvalue di diverso da uno dei seguenti tipi di comportamento è undefined:

  • ...
  • un char o un tipo unsigned char.

(la posizione esatta può essere diversa in altre versioni di C++, ma il significato è lo stesso.)

Ciò significa che si può prendere un vector<unsigned char> cache e accedere al suo contenuto che utilizzano la gamma [reinterpret_cast<char*>(cache.data()), reinterpret_cast<char*>(cache.data()) + cache.size()). (SB @Kerrek menzionato questo.)

Se si memorizza una vector<unsigned char> in Processor modo che corrisponda al tipo di ritorno di LoadFile, e _dataOperation() prende in realtà una serie di char (che significa una e una dimensione const char*), allora si può lanciare quando si 're passando l'argomento a _dataOperation()

Tuttavia, se _dataOperation() prende un vector<char> modo specifico e si memorizza un vector<unsigned char> cache, allora non può passaggio che reinterpret_cast<vector<char>&>(cache). (Ad esempio, @ André Puel è totalmente in errore. Non ascoltarlo.) Questo viola le regole di aliasing e il compilatore tenterà di far arrabbiare i tuoi clienti alle 2 del mattino.(E se questa versione del tuo compilatore non la gestisce, la prossima versione continuerà a provare.)

Un'opzione è, come hai detto, al modello LoadFile() e averlo restituito (o compilato) un vettore del tipo che vuoi Un altro è quello di copiare il risultato, per il quale la versione concisa è di nuovo il reinterpret_cast del vettore di origine .data(). [basic.fundamental] p1 menziona che "Per i tipi di carattere, tutti i bit della rappresentazione dell'oggetto partecipano alla rappresentazione del valore.", il che significa che non si perderanno dati con quello reinterpret_cast. Non vedo alcuna garanzia che nessun modello di uno unsigned char possa causare un trap se da reinterpret_cast'ed a char, ma non conosco nessun hardware o compilatore moderno che lo faccia.

+0

Grazie per una risposta completa. –

Problemi correlati