2010-07-16 27 views
77

¿Con qué propósito debo usar std::get_temporary_buffer? Estándar dice lo siguiente:¿Por qué necesito std :: get_temporary_buffer?

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 la función global ::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 la sintaxis de azúcar? ¿Por qué hay temporary en su nombre?


Un caso de uso se sugirió en el Dr. Dobb's Journal, July 01, 1996 para los algoritmos de ejecución:

Si no hay memoria intermedia puede ser asignado, o si es más pequeño que solicitó, el algoritmo sigue funcionando correctamente, simplemente se ralentiza .

+2

FYI, 'std :: get_temporary_buffer' estará en desuso en C++ 17. – Deqing

Respuesta

39

BS dice en "El C++ Programming Language" (§19.4.4, SE):

La idea es que un sistema puede llevar un número de buffers de tamaño fijo listo para una rápida Asignación para que solicite espacio para objetos n puede dar lugar a más de n. Sin embargo, también puede rendir menos, por lo que una forma de usar get_temporary_buffer() es solicitar mucho optimismo y luego usar lo que está disponible.
[...] Debido a que get_temporary_buffer() es de bajo nivel y es probable que esté optimizado para administrar búferes temporales, no se debe utilizar como una alternativa al nuevo o allocator :: allocate() para obtener almacenamiento a largo plazo.

También se inicia la introducción de las dos funciones con:

Algoritmos menudo requiere espacio temporal para un rendimiento aceptable.

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

Un anecdote en "From Mathematics to Generic Programming" menciona que Stepanov proporcionó una aplicación falsa marcador de posición en el diseño STL original, sin embargo:

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

+8

Parece que la implementación de VC++ de esto es simplemente un bucle que llama 'operator new' con argumentos sucesivamente menores hasta que la asignación tenga éxito. No hay optimizaciones especiales allí. – jalf

+2

@jalf, el mismo código en g ++ 4.2.4. –

+8

Lo mismo con g ++ 4.5: parece que fue bien intencionado pero ignorado por los proveedores. –

9

La norma dice que asigna almacenamiento para hastan elementos. En otras palabras, su ejemplo podría devolver un búfer lo suficientemente grande para 5 objetos solamente.

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.

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

responden puede ser menor que 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 base de necesidad mayor o igual a requieren.

2

Tal vez (solo una conjetura) 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).

Así que get_temporary_buffer podría ser una porción de memoria mayor de la que se necesita una vez (quizás haya muchos fragmentos listos para aceptar múltiples solicitudes), y cada vez que necesite memoria simplemente obtener uno de los trozos. Entonces la memoria no se fragmenta. chico biblioteca estándar

+1

pensamiento muy interesante. Aunque en la actualidad parece implementarse como * deja-hacer-hacer-algo-eso-funciona * en la mayoría de las implementaciones, esto podría muy bien respaldarse más e integrarse con el resto de las rutinas de administración de memoria. Yo voto por nosotros en realidad esperando que esto sea adecuado para él, y los comentarios de Bjarnes parecen insinuarlo también. –

+0

He buscado lo que Bjarne dice al respecto y dice que está diseñado para una asignación rápida sin inicialización. Por lo tanto, sería como un operador void * solo asignador (no inicializador) nuevo (size_t size), pero que es más rápido de asignar, ya que está asignado previamente. –

14

de Microsoft dice lo siguiente (here):

  • Podría quizás explique cuándo utilizar '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 (último - primero) * log (último - primer) intercambio, pero solo el número lineal de intercambia si hay suficiente memoria extra ". Cuando aparezcan 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 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.

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

0

¿Con qué propósito debo utilizar std::get_temporary_buffer?

The function está en desuso en C++ 17, por lo que la respuesta correcta es ahora "sin ningún propósito, no lo uso".

Cuestiones relacionadas