2009-10-19 10 views
9

Tengo un cliente de red con un método de solicitud que toma un std::streambuf*. Este método está implementado por boost::iostreams::copy -solo en una clase personalizada std::streambuf -deriva que sabe cómo escribir los datos en una API de red, que funciona muy bien. Esto significa que puedo transmitir un archivo a la solicitud sin necesidad de leerlo todo en la memoria.Transmitir desde std :: cadena sin hacer una copia?

Hay algunos casos, sin embargo, donde se deben enviar grandes bloques de datos que no están en un archivo, por lo que incluí una sobrecarga que toma una cadena. Para evitar la duplicación de todo el código de red en la transmisión, parecía obvio que debería configurar un streambuf que representara la cadena y llamar al otro método. La única manera de que pudiera averiguar para hacer este trabajo era algo así como:

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

Desafortunadamente, istringstream hace una copia de los datos, que en algunos casos es de varios megabytes. Tiene sentido en el caso general, por supuesto, si le das una referencia constante a algún objeto, no quieres que ese objeto asuma que puede continuar usando esa referencia.

trabajé alrededor de este con lo siguiente:

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

Esto parece funcionar bien, pero me pregunto si es realmente necesario. ¿Por qué std::istringstream no tiene una sobrecarga teniendo un std::string const *? ¿Hay una mejor manera de hacer esto?

Respuesta

4

La razón por la que está teniendo este problema es que std :: string no se adapta realmente a lo que está haciendo. Una mejor idea es usar el vector de char cuando pases datos en bruto. Si es posible, simplemente cambiaría todo para usar vector, usando vector :: swap y referencias a vectores como apropiado para eliminar toda tu copia. Si te gusta la iostreams/streambuf api, o si tienes que lidiar con algo que tenga un streambuf, sería trivial crear tu propio streambuf que use un vector, como el tuyo. Efectivamente haría lo mismo que usted con los mismos problemas que figuran en las otras respuestas, pero no estaría violando el contrato de la clase.

De lo contrario, creo que lo que tienes es probablemente la mejor manera de pasar un istringstream en todas partes.

+0

Una idea interesante. Una de las cosas que me gusta de la configuración existente es que puedo configurar una secuencia de entrada o salida personalizada derivando de 'std :: stringbuf' y solo tengo que anular una o dos funciones simples, underflow o' overflow' y ' sync', la clase base maneja toda la administración de buffer para mí. Sospecho que basar cosas de 'std :: vector' significaría que necesitaría considerablemente más código. De todos modos, podría usar 'swap', aunque necesitaría hacer que la persona que llama" abandonara "la cadena en vez de hacer una referencia constante. –

2

imho, la mejor opción es una clase en desuso std :: strstream

+0

Gracias, no sabía de eso. El único problema es que quiere un 'char *' en lugar de 'const char *', pero eso es bastante fácil de solucionar. –

Cuestiones relacionadas