2010-06-26 12 views
7

Ainsi istringstream copie le contenu d'une chaîne, lorsque initialisés par exemple non-copie istringstream

string moo("one two three four"); 
istringstream iss(moo.c_str()); 

Je me demandais s'il y a un moyen de faire std::istringstream utiliser la donnée c_str comme tampon sans copier les choses. De cette façon, il n'aura pas à copier de gros morceaux de mémoire avant de passer le std::istringstream& aux fonctions qui prennent istream& comme argument. Ce que j'ai essayé de faire est de convertir certaines fonctions qui prennent seulement std::ifstream& arguments (ils sont principalement des parseurs) en prenant istream& ainsi. Devrais-je créer ma propre sous-classe istream pour cela?

+0

Voir [cette réponse] (http: // stackoverflow.com/questions/2786816/how-to-create-c-istringstream-from-a-char-array-with-null0-characters/2786872 # 2786872) pour un moyen de le faire (fondamentalement identique à la solution @ Charles, mais l'emballage un 'istream' autour de lui pour plus de commodité). –

Répondre

3

Il est assez trivial d'écrire une classe std::streambuf de base qui lit une zone de mémoire donnée. Vous pouvez ensuite construire un istream à partir de cela et lire à partir de cela.

initializing a C++ std::istringstream from an in memory buffer?

Notez que la durée de vie du tampon a être c_str() est très limité, cependant, et il n'y a aucune garantie qu'un appel à c_str() veulent faire une copie bien que je ne connais pas d'implémentations où il Est-ce que.

+0

Ah, merci pour cela, je vais essayer. Ça a l'air beaucoup plus simple que ce que j'imaginais :) – kamziro

2

Il n'y a qu'une copie car le paramètre que vous transmettez, un const char*, nécessite la conversion au type d'argument du istringstream constructor.

Passez simplement le string sans appeler c_str().

istringstream iss(moo); 

Eh bien, cela n'empêche pas la copie complète, mais cela élimine une copie inutile. Pour éliminer complètement la copie, vous devrez réécrire std::stringbuf, ce qui évite spécifiquement de travailler directement sur le string que vous lui donnez.

2

Cela dépend de ce que fait une chaîne std ::. Selon 27.2.1/1 The class basic_istringstream<charT,traits,Allocator> ... uses a basic_stringbuf<charT,traits,Allocator> object to control the associated storage. Puisque la classe doit utiliser un objet, elle doit copier la chaîne dans cet objet. La vraie question n'est donc pas de savoir si un stringstream copie le contenu, mais si la construction d'une chaîne va copier le contenu ou implémenter une sorte de schéma de copie sur écriture.

3

le istrstream déprécié prend en charge cette fonctionnalité.

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

int main(int argc, char* argv[]) 
{ 
    string moo = "one two three four"; 
    istrstream istr(const_cast<char*>(moo.c_str()),moo.size()); 
    std::string line; 
    while(!istr.fail() && !istr.eof()){ 
     getline(istr,line,' '); 
     cout << line << "_"; 
    } 
    // prints: one_two_three_four_ 
} 
+0

L'utilisation de 'capacity()' est incorrecte, elle devrait être 'size()'. – sbi

+0

@sbi: mon mauvais, j'ai fait quelques tests avec strstream d'abord, était un reste de cela, bien c'est réparé maintenant. – smerlin

2

L'utilisation de istringstream n'est pas une solution satisfaisante, car cela copie l'ensemble du tampon.

Une réponse précédente suggère dépréciée istrstream, mais cela génère des avertissements et peut être retiré à l'avenir, une meilleure solution consiste à utiliser boost::iostreams:

boost::iostreams::stream<boost::iostreams::array_source> stream(moo.c_str(), moo.size()); 

Cela évite la copie du tampon de la même manière istrstream a fait et vous évite d'écrire votre propre classe de flux.