Asignadores
La biblioteca estándar de C++ usa los asignadores para controlar la asignación y desasignación de elementos almacenados en contenedores. Todos los contenedores de la biblioteca estándar de C++ excepto std::array
tienen un parámetro de plantilla de tipo allocator<Type>
, donde Type
representa el tipo del elemento contenedor. Por ejemplo, la clase vector
se declara como sigue:
template <
class Type,
class Allocator = allocator<Type>
>
class vector
La biblioteca estándar de C++ proporciona una implementación predeterminada para un asignador. En C++11 y versiones posteriores, el asignador predeterminado se actualiza para exponer una interfaz más pequeña. El nuevo asignador se denomina asignador mínimo. En particular, el miembro del asignador mínimo construct()
admite la semántica de movimiento, que puede mejorar considerablemente el rendimiento. En la mayoría de los casos, este asignador predeterminado debería ser suficiente. En C++11 todos los tipos y las funciones de la biblioteca estándar con un parámetro de tipo de asignador admiten la interfaz del asignador mínimo, incluyendo std::function
, shared_ptr, allocate_shared()
y basic_string
. Para más información sobre el asignador predeterminado, consulte allocator
(clase).
Escribir su propio asignador (C++11)
El asignador predeterminado usa new
y delete
para asignar y desasignar memoria. Si quiere emplear otro método de asignación de memoria, como el uso de memoria compartida, debe crear su propio asignador. Si quiere usar C++11 y tiene que escribir un asignador personalizado nuevo, haga que sea un asignador mínimo si es posible. Si ya ha implementado un asignador de estilo antiguo, considere la posibilidad de modificarlo para que sea un asignador mínimo y aprovechar la mayor eficacia del método construct()
que se proporcionará automáticamente.
Un asignador mínimo requiere mucha menos repetición y le permite centrarse en las funciones miembro allocate
y deallocate
, que hacen todo el trabajo. Al crear un asignador mínimo, implemente solo los miembros que se muestran en el ejemplo siguiente:
un constructor de copias de conversión (vea el ejemplo)
operator==
operator!=
allocate
deallocate
El miembro construct()
predeterminado de C++11 que se proporcionará reenvía directamente y habilita la semántica de transferencia; es mucho más eficaz en muchos casos que la versión anterior.
Advertencia
En tiempo de compilación, la biblioteca estándar de C++ usa la clase allocator_traits
para detectar los miembros que se hayan proporcionado explícitamente y proporciona una implementación predeterminada para todos los miembros que no están presentes. No interfiera en este mecanismo proporcionando una especialización de allocator_traits
para su asignador.
En el ejemplo siguiente se muestra una implementación mínima de un asignador que usa malloc
y free
. Tenga en cuenta el uso del nuevo tipo de excepción std::bad_array_new_length
que se produce si el tamaño de la matriz es menor que cero o mayor que el tamaño máximo permitido.
#pragma once
#include <stdlib.h> //size_t, malloc, free
#include <new> // bad_alloc, bad_array_new_length
#include <memory>
template <class T>
struct Mallocator
{
typedef T value_type;
Mallocator() noexcept {} //default ctor not required by C++ Standard Library
// A converting copy constructor:
template<class U> Mallocator(const Mallocator<U>&) noexcept {}
template<class U> bool operator==(const Mallocator<U>&) const noexcept
{
return true;
}
template<class U> bool operator!=(const Mallocator<U>&) const noexcept
{
return false;
}
T* allocate(const size_t n) const;
void deallocate(T* const p, size_t) const noexcept;
};
template <class T>
T* Mallocator<T>::allocate(const size_t n) const
{
if (n == 0)
{
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
void* const pv = malloc(n * sizeof(T));
if (!pv) { throw std::bad_alloc(); }
return static_cast<T*>(pv);
}
template<class T>
void Mallocator<T>::deallocate(T * const p, size_t) const noexcept
{
free(p);
}
Escribir su propio asignador (C++03)
En C ++03, cualquier asignador usado con contenedores de la biblioteca estándar de C++ debe implementar las definiciones de tipo siguientes:
const_pointer
const_reference
difference_type
pointer
rebind
reference
size_type
value_type
Además, cualquier asignador usado con contenedores de la biblioteca estándar de C++ debe implementar los siguientes métodos:
Constructor
Constructor de copias
Destructor
address
allocate
construct
deallocate
destroy
max_size
operator!=
operator==
Para más información sobre estas definiciones de tipos y métodos, consulte allocator
(clase).