Question

Est-il possible de lire un nombre connu d'octets directement dans un std :: string, sans créer de tampon temporaire pour le faire?

par exemple actuellement je peux le faire en

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;
Était-ce utile?

La solution

std :: string a une fonction redimensionner que vous pouvez utiliser, ou un constructeur qui fera de même:

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

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

Ceci n’a pas été testé et je ne sais pas si les chaînes sont obligées d’avoir un stockage contigu.

Autres conseils

Vous pouvez utiliser une combinaison de copy_n et d'un 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;
}

pas de copie, pas de hacks, pas de possibilité de dépassement, pas de comportement indéfini.

Vous pouvez utiliser quelque chose comme getline:

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

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

Je voudrais utiliser un vecteur comme tampon.

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());

Bien que vous vous en tiriez probablement avec une chaîne comme tampon (comme décrit par GMan). La norme ne garantit pas que les membres d'une chaîne se trouvent dans des emplacements consécutifs (vérifiez donc votre implémentation actuelle et mettez un gros commentaire à vérifier lors du transfert vers un autre compilateur / plate-forme).

Êtes-vous simplement en train d’optimiser la longueur du code ou d’essayer de vous en conserver une copie? Quel est le problème avec le tampon temporaire?

Je dirais que vous contournez les protections de la chaîne qui essaie d'écrire directement, faites-le comme ça. Si les performances de la copie sur std :: string vous inquiètent, car vous avez identifié un impact négatif sur les performances de votre application, je travaillerais directement avec char *.

EDIT: Faire plus en regardant ... initialisation de std :: string à partir de char * sans copie

Dans la deuxième réponse, il est dit assez clairement que vous ne pouvez pas atteindre ce que vous cherchez (ex.: peupler un std :: string sans itération sur le caractère * à copier.)

Examinez votre routine de chargement (postez-la ici peut-être?) et limitez les allocations: les nouvelles suppressions et les suppressions ne sont certainement pas gratuites, vous pouvez donc au moins gagner du temps si vous n'avez pas à recréer le tampon à tout moment. . Je trouve toujours utile de l'effacer en memset'ing le tampon à 0 ou à zéro en mettant fin au premier index du tableau à chaque itération, mais vous pouvez rapidement éliminer ce code dans l'intérêt de la performance une fois que vous avez confiance en votre algorithme.

Un moyen facile serait:

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top