2011-11-23 10 views
18

Tengo el origen para una biblioteca grande (> 250 archivos) que hace un uso intensivo de contenedores y cadenas STL. Necesito ejecutarlo en un entorno incrustado con un montón limitado, por lo que quiero asegurarme de que esta biblioteca en sí misma esté limitada en su uso de almacenamiento dinámico.Reemplazar el asignador STL predeterminado

La solución obvia es crear un asignador, pero modificar todo el código base para incluir el parámetro de plantilla del asignador es un gran trabajo de último recurso, y no deseable en caso de que quiera tomar una nueva versión de la fuente. Reemplazar globalmente nuevo y eliminar no es factible ya que afecta la imagen completa, no solo esta biblioteca.

Mi siguiente pensamiento fue un estúpido truco macro C, pero parece que no sería posible, aunque admito que no soy un macro autor inteligente.

Así que pensé "¿hay un compilador o un modificador pragma para especificar el asignador <> clase en tiempo de compilación"? Pero estoy abierto para cualquier cosa.

La siguiente pregunta que haré, si alguien puede encontrar una solución, es cómo hacer lo mismo para nuevo/eliminar dentro del conjunto de archivos que componen esta biblioteca.

Estoy usando el toolchain gcc 3.4.4 para ejecutar esto bajo Cygwin, con un objetivo de VxWorks, si eso genera alguna idea.

+0

gcc 3.4.4 Eso es lo suficientemente viejo como para ser etiquetado como "completamente roto". ¿Alguna razón por la que no cambias a una versión más nueva? – sehe

+0

Creo que en GCC eso es solo una simple macro en algún lugar de la red interna, que deberías poder cambiar. El valor predeterminado es el "nuevo asignador", pero GCC viene con varias alternativas, como el "asignador malloc" y un asignador de grupo y otras cosas. –

+0

Supongamos que puede crear un montón limitado y luego sobrecargar 'operator new' solo para esta biblioteca, por lo que todas las llamadas' operator new' en la biblioteca fueron a su montón limitado. ¿Qué comportamiento quieres cuando el montón limitado está lleno y se llama al sobrecargado 'operator new'? ¿Realmente querrías que fallara el 'operador nuevo' en esas circunstancias? No creo que lo haría, a menos que esa biblioteca todavía pueda funcionar cuando 'operator new' está fallando. Tal vez si la biblioteca es un caché de base de datos, o algo así. ¿Qué hace la biblioteca? –

Respuesta

6

que recurrieron al pre-procesador para obtener una posible solución, aunque en la actualidad se basa en la aplicación de GCC 3.4.4 para trabajar.

El CCG <memory> aplicación incluye el archivo <bits/allocator.h>, que a su vez contiene otro archivo <bits/c++allocator.h>, que define una macro que define la clase que implementa la clase base asignador por defecto.

Dado que se encuentra en un camino (/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/i686-pc-cygwin/bits) dependiente de la plataforma, no me siento (muy) sucia en suplantarlo con mi propia implementación "dependiente de la plataforma".

Así que solo creo una carpeta bits/ en la raíz de la ruta de inclusión de mi fuente, y luego creo el archivo c++allocator.h en esa carpeta. Defino que la macro requerida es el nombre de mi clase de asignador y funciona como un hechizo, ya que gcc busca mis rutas de inclusión antes de buscar en el sistema.

Gracias por todas sus respuestas. Creo que puedo ir con esta "solución", que solo funcionará siempre que esté usando 3.4.4 probablemente.

+0

alguna idea sobre cómo hago esto en Visual Studio? Intenté localizar el archivo de encabezado del asignador predeterminado, pero me perdí :) ¡gracias! – OSH

3

Así que pensé "¿hay un compilador o pragma modificador para especificar el asignador <> clase en tiempo de compilación"? Pero estoy abierto para cualquier cosa.

No, no hay.

Echa un vistazo a here.

Los asignadores son un argumento de plantilla en cada contenedor stl. Tendrá que cambiarlos. He hecho lo mismo en el pasado, cuando trabajaba en embedded. Te podría dar algunos consejos si quieres:

asignador plantilla básica:

namespace PFM_MEM { 
    template <class T> 
    class CTestInstAllocator { 
    public: 
     // type definitions 
     typedef size_t size_type; 
     typedef ptrdiff_t difference_type; 
     typedef T*  pointer; 
     typedef const T* const_pointer; 
     typedef T&  reference; 
     typedef const T& const_reference; 
     typedef T   value_type; 

     // rebind CTestInstAllocator to type U 
     template <class U> 
     struct rebind { 
      typedef CTestInstAllocator<U> other; 
     }; 

     // return address of values 
     pointer address (reference value) const { 
      return &value; 
     } 
     const_pointer address (const_reference value) const { 
      return &value; 
     } 

     /* constructors and destructor 
     * - nothing to do because the CTestInstAllocator has no state 
     */ 
     CTestInstAllocator() { 
     } 
     CTestInstAllocator(const CTestInstAllocator&) { 
     } 
     template <class U> 
     CTestInstAllocator (const CTestInstAllocator<U>&) { 
     } 
     ~CTestInstAllocator() { 
     } 

     // return maximum number of elements that can be allocated 
     size_type max_size() const { 
      return std::numeric_limits<size_t>::max()/sizeof(T); 
     } 

     // pvAllocate but don't initialize num elements of type T by using our own memory manager 
     pointer allocate (size_type num) { 
      /** 
      * pvAllocate memory custom memory allocation scheme 
      */ 
      return(pointer)(CPfmTestInstMemManager::pvAllocate(num*sizeof(T))); 
     } 
     // initialize elements of allocated storage p with value value 
     void construct (pointer p, const T& value) { 
      // initialize memory with placement new 
      new((void*)p)T(value); 
     } 

     // destroy elements of initialized storage p 
     void destroy (pointer p) { 
      // destroy objects by calling their destructor 
      p->~T(); 
     } 
     // vDeallocate storage p of deleted elements 
     void deallocate (pointer p, size_type num) { 
      /** 
      *Deallocate memory with custom memory deallocation scheme 
      */ 
      CPfmTestInstMemManager::vDeallocate((void*)p); 
     } 
    }; 

    // return that all specializations of this CTestInstAllocator are interchangeable 
    template <class T1, class T2> 
    bool operator== (const CTestInstAllocator<T1>&, 
     const CTestInstAllocator<T2>&) { 
      return true; 
    } 
    template <class T1, class T2> 
    bool operator!= (const CTestInstAllocator<T1>&, 
     const CTestInstAllocator<T2>&) { 
      return false; 
    } 
} 

Toma nota en particular en estas líneas:

/** 
* pvAllocate memory custom memory allocation scheme 
*/ 
return(pointer)(CPfmTestInstMemManager::pvAllocate(num*sizeof(T))); 

// vDeallocate storage p of deleted elements 
void deallocate (pointer p, size_type num) { 
/** 
*Deallocate memory with custom memory deallocation scheme 
*/ 
CPfmTestInstMemManager::vDeallocate((void*)p); 

Aquí es el lugar donde se llama a su nueva y eliminar qué trabajo en tu montón.

Podría darle un ejemplo de cómo construir un administrador de memoria básico que lo ayudará aún más.

+0

Así que está diciendo que no hay manera de decirle a STL que use un asignador personalizado globalmente; debe asegurarse de que cuando usa un tipo stl, lo defina con el asignador personalizado. ¿derecho? – OSH

+0

@OrenS. Bueno, para los compiladores específicos, puede haber una opción, pero estoy hablando de mi experiencia, solo. Estaba en el mismo lugar que el OP y tuve que hacer esto. Edita la respuesta corregida. – FailedDev

+0

@FailedDev, vi esa página antes de publicarla aquí y tuve esperanzas. Si pudiera averiguar cómo hacer que mi asignador arbitrario sea un asignador de "extensión", estaría dorado. Yo tampoco sé cómo hacer eso. Si sabes eso, nombraré a mi próximo perro "FailedDev" ... – Reilly

6

Usted podría beneficiarse del uso de EASTL (STL Enterprise Artes (parcial) aplicación)

EASTL -- Electronic Arts Standard Template Library

Esto fue pensada para el desarrollo/juego incrustado, en ambientes donde global heap is really scarce, non-existent or problematic in general.

El modelo asignador de EASTL se inspiró en (o se asemeja a ?) Las ideas en la famosa publicación Towards a Better Allocator Model (PDF).

El EASTL se presta bien para asignadores personalizados. De hecho, no se envía con un asignador, por lo que proporcionar (un mínimo) uno es requiere para incluso obtener su aplicación para vincular.

Aquí es el repositorio GitHub para EASTL: https://github.com/paulhodge/EASTL

+0

Esta es una posible solución, aunque tendría que editar EASTL o mi biblioteca debido a los espacios de nombres std vs eastl. – Reilly

Cuestiones relacionadas