Alokatory
Alokatory są używane przez bibliotekę standardową języka C++ do obsługi alokacji i cofania przydziału elementów przechowywanych w kontenerach. Wszystkie kontenery biblioteki standardowej C++ z wyjątkiem std::array
parametru szablonu typu allocator<Type>
, gdzie Type
reprezentuje typ elementu kontenera. Na przykład vector
klasa jest zadeklarowana w następujący sposób:
template <
class Type,
class Allocator = allocator<Type>
>
class vector
Biblioteka Standardowa języka C++ udostępnia domyślną implementację alokatora. W języku C++11 lub nowszym domyślny alokator jest aktualizowany w celu uwidocznienia mniejszego interfejsu; nowy alokator jest nazywany minimalnym alokatorem. W szczególności element członkowski minimalnego alokatora construct()
obsługuje semantykę przenoszenia, co może znacznie poprawić wydajność. W większości przypadków ten domyślny alokator powinien być wystarczający. W języku C++11 wszystkie typy i funkcje biblioteki standardowej, które przyjmują parametr typu alokatora, obsługują minimalny interfejs alokatora, w tym std::function
, shared_ptr, allocate_shared()
i basic_string
. Aby uzyskać więcej informacji na temat domyślnego alokatora, zobacz allocator
Klasa.
Pisanie własnego alokatora (C++11)
Domyślny alokator używa funkcji new
i delete
do przydzielania i cofania przydziału pamięci. Jeśli chcesz użyć innej metody alokacji pamięci, takiej jak użycie pamięci udostępnionej, musisz utworzyć własny alokator. Jeśli używasz języka C++11 i musisz napisać nowy alokator niestandardowy, jeśli jest to możliwe, dokonaj minimalnej alokacji. Nawet jeśli zaimplementowano już alokator starego stylu, rozważ zmodyfikowanie go jako minimalnej alokatora w celu skorzystania z bardziej wydajnej construct()
metody, która zostanie udostępniona automatycznie.
Minimalny alokator wymaga znacznie mniej standardowy i umożliwia skupienie się na allocate
funkcjach składowych i deallocate
, które wykonują całą pracę. Podczas tworzenia minimalnej alokatora nie implementuj żadnych elementów członkowskich, z wyjątkiem elementów przedstawionych w poniższym przykładzie:
konwertowanie konstruktora kopiowania (zobacz przykład)
operator==
operator!=
allocate
deallocate
Domyślny construct()
element członkowski języka C++11, który zostanie udostępniony w celu zapewnienia doskonałego przekazywania i umożliwia semantyka przenoszenia; jest znacznie bardziej wydajny w wielu przypadkach niż starsza wersja.
Ostrzeżenie
W czasie kompilacji biblioteka standardowa języka C++ używa allocator_traits
klasy do wykrywania, które elementy członkowskie zostały jawnie podane i zapewnia domyślną implementację dla wszystkich elementów członkowskich, które nie są obecne. Nie ingeruj w ten mechanizm, zapewniając specjalizację allocator_traits
dla alokatora!
W poniższym przykładzie pokazano minimalną implementację alokatora używającego elementów malloc
i free
. Zwróć uwagę na użycie nowego typu std::bad_array_new_length
wyjątku, który jest zgłaszany, jeśli rozmiar tablicy jest mniejszy niż zero lub większy niż maksymalny dozwolony rozmiar.
#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);
}
Pisanie własnego alokatora (C++03)
W języku C++03 każdy alokator używany z kontenerami biblioteki standardowej języka C++ musi implementować następujące definicje typów:
const_pointer
const_reference
difference_type
pointer
rebind
reference
size_type
value_type
Ponadto każdy alokator używany z kontenerami biblioteki standardowej języka C++ musi implementować następujące metody:
Konstruktor
Konstruktor kopiujący
Destruktor
address
allocate
construct
deallocate
destroy
max_size
operator!=
operator==
Aby uzyskać więcej informacji na temat tych definicji typów i metod, zobacz allocator
Klasa.