Pergunta

Eu tenho uma estrutura de dados definida como

struct myDataStruct
{
   int32_t header;
   int16_t data[8];
}

E eu quero pegar um fluxo de personagens e transformá -lo em um fluxo mydata. Qual classe de fluxo devo estender? Eu gostaria de criar uma classe de fluxo personalizada para que eu possa fazer coisas como

myDataStruct myData;
myDataStruct myDataArray[10];

myDataStream(ifstream("mydatafile.dat"));
myDataStream.get(myData);
myDataStream.read(myDataArray, 10);
Foi útil?

Solução

Ao invés de myDataStream.get(myData), o que você faz é sobrecarga operator>> Para o seu tipo de dados:

std::istream& operator>>(std::istream& is, myDataStruct& obj)
{
  // read from is into obj
  return is;
}

Se você quiser ler uma matriz, basta escrever um loop:

for( std::size_t idx=0; idx<10; ++idx ) 
{
   myDataStruct tmp;
   if( is >> tmp )
     myDataArray[idx] = tmp;
   else
     throw "input stream broken!";
}

Usando um modelo de função, você também deve sobrecarregar o operador para matrizes no lado direito (mas isso eu nunca tentei):

template< std::size_t N >
std::istream& operator>>(std::istream& is, myDataStruct (&myDataArray)[N])
{
  // use loop as above, using N instead of the 10
}

Mas não consigo decidir se isso é lindo ou desprezível.

Outras dicas

Se você estiver trabalhando com entrada não formatada, provavelmente deve ler diretamente em forma binária. Normalmente, você usaria alguma diretiva específica do compilador para criar estruturas de dados sem preenchimento e, em seguida, basta ler/gravar em um arquivo.

// Gcc
#pragma pack(1) // option 1: pragmas
struct frame {
   std::uint32_t header;
   std::uint16_t data[8];
} __attribute((packed)); // option 2: packed attribute
#pragma pack(0)

bool operator==( data const & lhs, data const & rhs )
{
   bool result = lhs.header == rhs.header;
   for ( int i = 0; i < 8; ++i )
   {
      result &= lhs.data[i] == rhs.data[i];
   }
   return result;
}

int main()
{
   frame data = { 10, 1, 2, 3, 4, 5, 6, 7, 8 };

   std::ofstream out( "data.bin", ofstream::binary );
   out.write( reinterpret_cast<char*>(&data), sizeof(data) );
   out.close();

   std::ifstream in( "data.bin", ifstream::binary );
   frame readed;
   in.read( reinterpret_cast<char*>(&readed), sizeof(readed) );
   in.close();

   std::cout << (readed == data) << std::endl; // 1
}

A diretiva do compilador para desativar o preenchimento para o VS pode ser diferente (acredito que a diretiva Pragma trabalha no GCC e no VS, mas sempre usei o atributo).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top