2009-10-19 13 views
9

Mam klienta sieci z metodą żądania, która ma std::streambuf*. Ta metoda jest implementowana przez boost::iostreams::copy -przy użyciu niestandardowej klasy std::streambuf, która wie, jak zapisać dane w sieciowym interfejsie API, który działa doskonale. Oznacza to, że mogę przesłać plik do żądania bez potrzeby wczytywania go do pamięci.Strumień ze std :: string bez tworzenia kopii?

Są jednak przypadki, w których należy wysłać duże bloki danych, których nie ma w pliku, dlatego uwzględniłem przeciążenie, które pobiera ciąg znaków. Aby uniknąć duplikowania całego kodu sieciowego w strumieniu, wydawało się oczywiste, że powinienem ustawić streambuf reprezentujący ciąg i wywołać inną metodę. Jedynym sposobem mogę dowiedzieć się do tej pracy było coś takiego:

std::istringstream ss(data); 
send(ss.rdbuf()); 

Niestety istringstream tworzy kopię danych, które w niektórych przypadkach kilka megabajtów. Ma to sens w ogólnym przypadku, oczywiście, jeśli przekażesz odwołanie do jakiegoś obiektu, nie chcesz tego obiektu, zakładając, że może on nadal używać tego odniesienia.

Pracowałem wokół to z następujących powodów:

struct zerocopy_istringbuf 
    : public std::stringbuf 
{ 
    zerocopy_istringbuf(std::string const* s) 
     : std::stringbuf(std::ios::in) 
    { 
     char* p = const_cast<char*>(s->c_str()); 
     setg(p, p, p + s->length()); 
    } 
}; 

... 

send(&zerocopy_istringbuf(data)); 

To wydaje się działać dobrze, ale zastanawiam się, czy to naprawdę konieczne. Dlaczego std::istringstream nie ma przeciążenia, biorąc std::string const *? Czy jest lepszy sposób to zrobić?

Odpowiedz

4

Powodem, dla którego masz ten problem, jest to, że std :: string nie pasuje do tego, co robisz. Lepszym pomysłem jest wykorzystanie wektora znaku przy przekazywaniu nieprzetworzonych danych. Jeśli to możliwe, po prostu zmieniłbym wszystko, by użyć wektora, używając wektorów :: zamiany i odniesień do wektorów jako odpowiednich, aby wyeliminować całe twoje kopiowanie. Jeśli podoba Ci się aplety iostreams/streambuf, lub jeśli masz do czynienia z czymś, co wymaga streambuf, to byłoby trywialnie stworzyć własny strumień, który używa wektora, takiego jak twój. Skutecznie zrobiłoby to samo, co robisz z tymi samymi problemami, które wymieniono w innych odpowiedziach, ale nie naruszyłoby to umowy klasy.

W przeciwnym razie, myślę, że to, co masz, jest prawdopodobnie najlepszym sposobem na pokonanie wszędzie wokół istringstream.

+0

Ciekawy pomysł. Jedną z rzeczy, które podoba mi się w istniejącej konfiguracji, jest to, że mogę skonfigurować niestandardowy strumień wejściowy lub wyjściowy, wywodząc się z 'std :: stringbuf' i mam tylko nadpisać jedną lub dwie proste funkcje, niedomiar lub' przepełnienie' i ' sync', klasa podstawowa obsługuje dla mnie całe zarządzanie buforami. Podejrzewam, że opieranie rzeczy 'std :: vector' oznaczałoby, że potrzebowałbym znacznie więcej kodu. Być może i tak będę mógł użyć 'swap', chociaż potrzebuję abonenta" zrezygnować "z ciągu, zamiast przekazywać stałe odniesienie. –

2

imho, najlepszym wyborem jest przestarzała klasa std :: strstream

+0

Dzięki, nie wiedziałem o tym. Jedynym problemem jest to, że chce "char *" zamiast "const char *", ale to dość łatwe do obejścia. –

Powiązane problemy