2009-04-23 14 views
14
int main(void) 
{ 
    std::string foo("foo"); 
} 

Según tengo entendido, el código anterior usa el asignador predeterminado para llamar al nuevo. Entonces, aunque std :: string foo está asignado en la pila, el buffer interno dentro de foo se asigna en el montón.¿Cómo asigno una cadena std :: en la pila usando la implementación de cadena de glibc?

¿Cómo puedo crear una cadena que se asigna por completo en la pila?

+0

Permítanme enmendar eso a "¿cómo puedo crear una std :: basic_string que esté asignada por completo en la pila?" – poindexter

+0

Solo para hacer un enlace a una pregunta similar: http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage –

Respuesta

19

que quería hacer simplemente esto mismo hace poco y encontró el siguiente código iluminando:

Chronium's stack_container.h

Se define un nuevo std::allocator que puede proporcionar la asignación basado en la pila para la asignación inicial de almacenamiento para contenedores STL. Terminé encontrando una forma diferente de resolver mi problema en particular, así que en realidad no usé el código, pero tal vez te sea útil. Asegúrese de leer los comentarios en el código con respecto al uso y las advertencias.

Para aquellos que han cuestionado la utilidad y la cordura de hacer esto, tenga en cuenta:

  • A menudo se sabe a priori que la cadena tiene un tamaño máximo razonable. Por ejemplo, si la cadena va a almacenar un entero de 32 bits con formato decimal, sabrá que no necesita más de 11 caracteres para hacerlo. No hay necesidad de una cadena que pueda crecer dinámicamente hasta un tamaño ilimitado en ese caso.
  • La asignación de la pila es más rápida en muchos casos que la asignación desde el montón.
  • Si la cadena se crea y destruye con frecuencia (supongamos que es una variable local en una función de utilidad comúnmente utilizada), la asignación desde la pila en lugar del montón evitará la fragmentación inductora en el asignador de montón. Para las aplicaciones que usan mucha memoria, esto podría ser un cambio de juego.

Algunas personas han comentado que una cadena que usa la asignación basada en la pila no será std::string como si esto de alguna manera disminuyera su utilidad. Es cierto que no puede usar los dos indistintamente, por lo que no podrá pasar su stackstring a funciones que esperan un std::string. Pero (si lo haces bien), usted será capaz de utilizar todas las mismas funciones miembro en su stackstring que se utiliza ahora en std::string, como find_first_of(), append(), etc. begin() y end() todavía no tendrán ningún problema, por lo que será capaz de usar muchos de los algoritmos STL. Claro, no será std::string en el sentido más estricto, pero seguirá siendo una "cadena" en el sentido práctico, y aún será bastante útil.

+0

Gracias por el puntero a algún código interesante. –

+1

Puede usar muchos de los algoritmos STL en una matriz vacía de caracteres en la pila, pero alguien sugirió eso y se votó negativamente. El interlocutor tendrá que decidir qué características de std :: string necesita ... –

+2

Esto no funciona para std :: basic_string de glibc, llama al constructor predeterminado del Allocator, que StackAllocator no admite. – poindexter

0

Sospecho que hacer algo así sería difícil de hacer, me pregunto por qué quieres hacerlo? Para asignar algo completamente en la pila, el compilador necesita saber en tiempo de compilación cuál es el tamaño exacto de la cosa: en su ejemplo, necesitaría saber no solo el tamaño de los metadatos std::string, sino también el tamaño de los datos de cadena. sí mismo. Esto no es demasiado flexible, es probable que necesite diferentes tipos de cadenas de caracteres dependiendo del tamaño de los datos de cadena que desea incluir en ella, no es que sea imposible de hacer, solo que podría complicar un poco las cosas.

+1

"probablemente necesites una cadena diferente tipos que dependen del tamaño de los datos de cadena que desea incluir en él ". Bienvenido a Symbian! –

-3
  • std :: string siempre gestionará su almacenamiento interno con new/delete.
  • No estoy seguro de por qué su pregunta contiene implementación de cadenas de glibc. La implementación de cadena de la biblioteca estándar de C++ no tiene nada que ver con glibc.
  • La única manera de almacenar una cadena en la pila es usar una matriz C char en la pila (como se describe en Shhnap). Pero eso probablemente no es lo que quiere de todos modos :-)
+0

¿Hay realmente algo en el estándar con respecto al primer punto? AFAIK, la implementación interna es libre de hacer pequeñas optimizaciones de tamaño de cadena y no implicar un montón. –

+2

Majkara es correcto, las cadenas pequeñas (<16 caracteres en la implementación de MSVC) generalmente se asignan en la pila y no implican ninguna asignación de memoria de montón. – newgre

+0

std :: string define la interfaz, no la implementación. Específicamente pregunto sobre la implementación de glibc porque es con lo que estoy trabajando. Si estuviera usando la implementación de MSVC, no haría esta pregunta. Afortunadamente, recibí una respuesta que es independiente de la implementación. – poindexter

11

El problema es que std::basic_string tiene un parámetro de plantilla para el asignador. Pero std::string no es una plantilla y no tiene parámetros.

Entonces, en principio podría usar una instanciación de std::basic_string con un asignador que utiliza memoria en la pila, pero no sería un std::string. En particular, no obtendría el polimorfismo de tiempo de ejecución, y no podría pasar los objetos resultantes a funciones que esperan un std::string.

+1

No estoy seguro de cómo funcionaría eso? Exactamente, ¿cómo propone que el asignador modifique el marco de pila de su llamante?Simplemente hacer un alloca() en el asignador no funcionará porque esa memoria se liberaría automáticamente cuando el asignador devuelve el puntero, o cuando el constructor de std :: string retorna si el asignador estaba en línea. –

+0

Pásame :-) –

+1

Tienes toda la razón, el asignador solo podría funcionar porque no dijo * dónde * en la pila de datos que quería que fuera la cadena. El asignador necesitaría acceder a un bloque de pila a través de datos de instancia. Un poco como las librerías seguras de DJB (C, no C++), que usan un bloque limitado de espacio de pila porque es una manera económica y fácil de limitar el uso de memoria por subproceso –

4

No puede. Excepto ...

std::string es una instancia de

std::basic_string<class CharType, 
        class Traits=char_traits<CharType>, 
        class Allocator=allocator<CharType> > 

concebiblemente podría definir una clase que utiliza Allocator alloca para la gestión de la memoria. Esto solo funcionaría si el mismo Allocator y los métodos basic_string que lo invocan directa o indirectamente, son todos inline. Un objeto basic_string creado con este asignador no sería ser a std::string, pero se comportaría (en su mayoría) de esa manera. Sin embargo, esto sería una buena cantidad de trabajo para obtener ganancias limitadas. Específicamente, usar esta clase para devolver valores de una función sería un movimiento que limita la carrera.

No tengo idea por qué usted o alguien más querría hacer esto.

+2

+1, módulo el comentario a mi respuesta, que alloca realmente no lo hace porque std :: basic_string llama al asignador, por lo que es "demasiado tarde" para usar alloca. Sin embargo, no puedo recordar cómo alloca interactúa con la alineación: tal vez con cantidades brutales, podría funcionar para una implementación de STL y configuraciones del compilador en particular. –

+0

El compilador tendría que salirse de su camino para dar a los métodos en línea su propio marco de pila. OTOH, hacer apuestas sobre eso es * otro * movimiento que limita la carrera. –

+1

alloca no es POSIX, así que ni siquiera voy a considerarlo. En cuanto a por qué alguien querría hacer esto, te señalo la respuesta de Eric Melski. – poindexter

Cuestiones relacionadas