Pergunta

Existe uma maneira de ler um número conhecido de bytes, diretamente em uma std :: string, sem a criação de um buffer temporário para fazê-lo?

por exemplo, atualmente eu posso fazer isso por

boost::uint16_t len;
is.read((char*)&len, 2);
char *tmpStr = new char[len];
is.read(tmpStr, len);
std::string str(tmpStr, len);
delete[] tmpStr;
Foi útil?

Solução

std::string tem uma função resize você poderia usar, ou um construtor que vai fazer o mesmo:

boost::uint16_t len;
is.read((char*)&len, 2);

std::string str(len, '\0');
is.read(&str[0], len);

Esta é testado, e eu não sei se cordas são obrigados a ter armazenamento contíguo.

Outras dicas

Você pode usar uma combinação de copy_n e um insert_iterator

void test_1816319()
{
    static char const* fname = "test_1816319.bin";
    std::ofstream ofs(fname, std::ios::binary);
    ofs.write("\x2\x0", 2);
    ofs.write("ab", 2);
    ofs.close();

    std::ifstream ifs(fname, std::ios::binary);
    std::string s;
    size_t n = 0;
    ifs.read((char*)&n, 2);
    std::istream_iterator<char> isi(ifs), isiend;
    std::copy_n(isi, n, std::insert_iterator<std::string>(s, s.begin()));
    ifs.close();
    _unlink(fname);

    std::cout << s << std::endl;
}

nenhuma cópia, sem hacks, sem possibilidade de superação, nenhum comportamento indefinido.

Você pode usar algo como getline:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string str;
  getline (cin,str,' ');
}

Gostaria de usar um vetor como o buffer.

boost::uint16_t len;
is.read((char*)&len, 2); // Note if this file was saved from a different architecture 
                         // then endianness of these two bytes may be reversed.

std::vector buffer(len);  // uninitialized.
is.read(&buffer[0], len);

std::string  str(buffer.begin(),buffer.end());

Embora provavelmente você vai fugir com o uso de uma corda como o tampão (como descrito por GMan). Não é garantido pela norma que um cordas membros estão em locais consecutivos (de modo a verificar a sua implementação atual e colocar um grande comentário que ele precisa verificar ao portar para outro compilador / plataforma).

Você está apenas otimizando comprimento de código ou tentando salvar a si mesmo uma cópia aqui? O que há de errado com o buffer temporário?

Eu diria que você está realmente contornar as proteções da corda tentando escrever diretamente fazê-lo assim. Se você está preocupado com o desempenho da cópia para um std :: string, porque você identificou que é de alguma forma afetar o desempenho de sua aplicação, eu trabalhar diretamente com o caractere *.

EDIT: Fazer mais olhar ... Inicializar std :: string de char * sem cópia

Na segunda resposta, é afirmado muito categoricamente que você não pode conseguir o que você está olhando para conseguir (ie. Preencher um std :: string sem uma iteração sobre o char * para copiar.)

Dê uma olhada em sua rotina de carga (postá-lo aqui, talvez?) E minimizar alocações: nova e excluir certamente não são livres para que você possa, pelo menos, poupar algum tempo se você não tem que recriar o buffer constantemente . Eu sempre achei apagar útil lo por memset'ing buffer para 0 ou nulo que encerra o primeiro índice do array cada iteração, mas você pode eliminar rapidamente que o código do interesse de desempenho uma vez que você está confiante em seu algoritmo.

Uma maneira fácil seria:

std::istream& data
const size_t dataSize(static_cast<size_t>(data.rdbuf()->in_avail()));
std::string content;
content.reserve( dataSize);
data.read(&content[0], dataSize);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top