c++ memory-management stl buffer temporary

c++ - ¿Por qué necesito std:: get_temporary_buffer?



memory-management stl (6)

¿Con qué propósito debería usar std::get_temporary_buffer?

std::get_temporary_buffer está obsoleta en C ++ 17, por lo que la respuesta correcta ahora es "sin propósito, no lo use".

¿Con qué propósito debería usar std::get_temporary_buffer ? Standard dice lo siguiente:

Obtiene un puntero al almacenamiento suficiente para almacenar hasta n objetos T adyacentes.

Pensé que el búfer se asignará a la pila, pero eso no es cierto. De acuerdo con el estándar C ++, este búfer no es temporal. ¿Qué ventajas tiene esta función sobre el ::operator new global function ::operator new , que tampoco construye los objetos? ¿Tengo razón en que las siguientes afirmaciones son equivalentes?

int* x; x = std::get_temporary_buffer<int>( 10 ).first; x = static_cast<int*>( ::operator new( 10*sizeof(int) ) );

¿Esta función solo existe para el azúcar de sintaxis? ¿Por qué hay temporary en su nombre?

Se sugirió un caso de uso en el Dr. Dobb''s Journal, el 1 de julio de 1996, para implementar algoritmos:

Si no se puede asignar un búfer, o si es más pequeño de lo solicitado, el algoritmo aún funciona correctamente, simplemente se ralentiza.


El estándar dice que asigna almacenamiento para hasta n elementos. En otras palabras, su ejemplo podría devolver un búfer lo suficientemente grande para 5 objetos solamente.

Sin embargo, parece bastante difícil imaginar un buen caso de uso para esto. Quizás si está trabajando en una plataforma muy limitada por la memoria, es una forma conveniente de obtener "la mayor cantidad de memoria posible".

Pero en una plataforma tan limitada, me imagino que omitiría el asignador de memoria tanto como fuera posible, y usaría un grupo de memoria o algo sobre lo que tuviera control total.


Quizás (solo una suposición) tiene algo que ver con la fragmentación de la memoria. Si continúa asignando y desasignando la memoria temporal, pero cada vez que lo hace asigna una memoria prevista a largo plazo después de asignar la temperatura, pero antes de desasignarla, puede terminar con un montón fragmentado (supongo).

Por lo tanto, el get_temporary_buffer podría ser una porción de memoria mayor a la que usted necesita, asignada una vez (quizás haya muchos fragmentos listos para aceptar múltiples solicitudes), y cada vez que necesite memoria solo obtendrá una de las trozos. Entonces la memoria no se fragmenta.


Stroustrup dice en "El lenguaje de programación C ++" ( §19.4.4 , SE):

La idea es que un sistema puede mantener una serie de búferes de tamaño fijo listos para una asignación rápida, de modo que el espacio solicitado para n objetos puede generar espacio para más de n . Sin embargo, también puede rendir menos, por lo que una forma de usar get_temporary_buffer() es pedir mucho optimismo y luego usar lo que está disponible.
[...] Debido a que get_temporary_buffer() es de bajo nivel y es posible que se optimice para administrar búferes temporales, no se debe utilizar como una alternativa a nuevo o allocator :: allocate () para obtener almacenamiento a más largo plazo.

También comienza la introducción a las dos funciones con:

Los algoritmos a menudo requieren espacio temporal para funcionar aceptablemente.

... pero no parece proporcionar una definición de temporal o de más largo plazo en ninguna parte.

Una anecdote en "De las Matemáticas a la Programación Genérica" menciona que Stepanov proporcionó una implementación de marcador de posición falsa en el diseño STL original, sin embargo:

Para su sorpresa, descubrió años más tarde que todos los principales proveedores que proporcionan implementaciones de STL siguen utilizando esta terrible implementación [...]


Tipo de biblioteca estándar de Microsoft dice lo siguiente ( here ):

  • ¿Podría explicarnos cuándo usar ''get_temporary_buffer''?

Tiene un propósito muy especializado. Tenga en cuenta que no arroja excepciones, como new (nothrow), pero tampoco construye objetos, a diferencia de new (nothrow).

Es utilizado internamente por el STL en algoritmos como stable_partition (). Esto sucede cuando hay palabras mágicas como N3126 25.3.13 [alg.partitions] / 11: stable_partition () tiene complejidad "A lo sumo (primero - primero) * log (último - primer) swaps, pero solo el número lineal de swaps si hay es suficiente memoria extra ". Cuando aparecen las palabras mágicas "si hay suficiente memoria extra", el STL usa get_temporary_buffer () para intentar adquirir espacio de trabajo. Si puede, entonces puede implementar el algoritmo de manera más eficiente. Si no puede, porque el sistema se está ejecutando peligrosamente cerca de la falta de memoria (o los rangos involucrados son enormes), el algoritmo puede recurrir a una técnica más lenta.

El 99.9% de los usuarios de STL nunca necesitarán saber acerca de get_temporary_buffer ().


ptrdiff_t request = 12 pair<int*,ptrdiff_t> p = get_temporary_buffer<int>(request); int* base = p.first; ptrdiff_t respond = p.sencond; assert( is_valid( base, base + respond ) );

responder puede ser menor que la solicitud .

size_t require = 12; int* base = static_cast<int*>( ::operator new( require*sizeof(int) ) ); assert( is_valid( base, base + require ) );

el tamaño real de la base debe ser mayor o igual a requerir .