Benutzerdefinierte Speicherzuweisung für STL-Container

STL- und STL-Erweiterungsklassen akzeptieren jetzt zusätzliche Vorlagenzuweisungsparameter. Die Standardwerte für Allocator-Parameter stammen aus der C++-Standardbibliothek std::allocator<T>. Sie können auch Ihren eigenen Allokator bereitstellen, um die Speicherverwaltung in Ihrer Anwendung anzupassen. Um Ihre eigene Vorlagenklasse als Allokator bereitzustellen, muss die Vorlage einer bestimmten Schnittstelle einschließlich Mitgliedsfunktionen und Typdefinitionen sowie deren syntaktischen und semantischen Anforderungen entsprechen.

Hier ist ein teilweiser Codeausschnitt eines einfachen Allokators:

    template <class T>
    class my_allocator 
    {
      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;

      template <class U> 
      struct rebind { typedef allocator<U> other; };
  
      // remaining member functions described below
      // ...
    };

Der Rebind-Member ermöglicht es dem Container, einen Allokator für einen beliebigen Datentyp zu erstellen. Der Allokatortyp wird durch die Vorlagenparameter bestimmt. Beispielsweise muss der Container möglicherweise andere Typen als T zuweisen (z. B. Listenknoten oder Hash-Buckets). In diesem Fall kann der Container den richtigen Typ erhalten, normalerweise mithilfe einer Typdefinition:

typedef A::rebind<Node>::other  Node_Allocator;

Die Allocator-Vorlagenklasse muss die oben genannten Anforderungen erfüllen. Darüber hinaus müssen folgende Funktionen implementiert werden:

Konstrukteur

    my_allocator() throw();     
    my_allocator (const allocator&) throw ();     
    template <class U>     
    my_allocator(const my_allocator<U>&);

Zerstörer

~my_allocator();

Aufgabenverwalter

    template <class U>     
    my_allocator& operator=(const my_allocator<U>&) throw();

öffentliche Mitgliedsfunktion

pointer address(reference r) const;

Gibt die Adresse eines Zeigertyps zurück. Diese Funktion und die folgende Funktion werden verwendet, um die Referenz r in einen Zeiger umzuwandeln.

const_pointer address(const_reference r) const;

pointer allocate(size_type n,
allocator<U>::const_pointer hint=0);

Speicherplatz für n Werte zuweisen. Verwenden Sie nach Möglichkeit den Wert von hint, um den Speicherort zu optimieren.

void deallocate(pointer);

Zerstören Sie einen Speicherplatz (gepaart mit Allocate).

size_type max_size();

Gibt den maximal verfügbaren Speicherplatz zurück (verfügbaren Speicherplatz zuweisen).

void construct(pointer p, const_reference val);

Konstruieren Sie ein Objekt der Klasse (Vorlagenparameter T) an einer bestimmten Position (der Position von p) und verwenden Sie den Wert von val, wenn Sie den Konstruktor von T aufrufen.

void destroy(pointer p);

Rufen Sie den Destruktor für den Wert auf, auf den p zeigt.

Das folgende Beispiel definiert einen einfachen benutzerdefinierten Allokator. Dies kann zum Testen der Compiler- oder Standard-C++-Bibliotheksunterstützung für benutzerdefinierte Allokatoren verwendet werden. Es prüft, ob die im Code übergebenen Allokatorparameter tatsächlich verwendet werden:

#include <rw/tvdlist.h>
#include <rw/cstring.h>
#include <iostream>

template <class T>
class my_allocator
{
public:
  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;

  my_allocator() {}
  my_allocator(const my_allocator&) {}



  pointer   allocate(size_type n, const void * = 0) {
              T* t = (T*) malloc(n * sizeof(T));
              std::cout
              << "  used my_allocator to allocate   at address "
              << t << " (+)" << std::endl;
              return t;
            }
  
  void      deallocate(void* p, size_type) {
              if (p) {
                free(p);
                std::cout
                << "  used my_allocator to deallocate at address "
                << p << " (-)" << 
                std::endl;
              } 
            }

  pointer           address(reference x) const { return &x; }
  const_pointer     address(const_reference x) const { return &x; }
  my_allocator<T>&  operator=(const my_allocator&) { return *this; }
  void              construct(pointer p, const T& val) 
                    { new ((T*) p) T(val); }
  void              destroy(pointer p) { p->~T(); }

  size_type         max_size() const { return size_t(-1); }

  template <class U>
  struct rebind { typedef my_allocator<U> other; };

  template <class U>
  my_allocator(const my_allocator<U>&) {}

  template <class U>
  my_allocator& operator=(const my_allocator<U>&) { return *this; }
};

int main()
{
  const int numItems = 100;
  std::cout << "\nCreating a RWTValDlist with a default allocator"
            << std::endl;

  RWTValDlist<RWCString> regular;


  std::cout << "\nInserting " << numItems
            << " items" << std::endl;

  for (int i = 0; i < numItems; ++i) {
    regular.insert(RWCString('a' + i, i));
  }


  std::cout << "\n\nCreating a RWTValDlist with my_allocator type"
            << std::endl;

  RWTValDlist<RWCString, my_allocator<RWCString> > custom;

  std::cout << "\nInserting " << numItems
            << " items\n" << std::endl;

  for (int i = 0; i < numItems; ++i) {
    custom.insert(RWCString('a' + i, i));
  }
  
  return 0;
}

Programmausgabe:

Creating a RWTValDlist with a default allocator

Inserting 100 items

Creating a RWTValDlist with my_allocator type
  used my_allocator to allocate   at address 0080ABD0 (+)
  used my_allocator to allocate   at address 0080AC08 (+)

Inserting 100 items

  used my_allocator to allocate   at address 0080AC40 (+)
  used my_allocator to allocate   at address 0080AC78 (+)
  used my_allocator to allocate   at address 0080C6F0 (+)
  used my_allocator to allocate   at address 0080C728 (+)
  used my_allocator to allocate   at address 0080FB28 (+)
  used my_allocator to allocate   at address 00820068 (+)
  used my_allocator to deallocate at address 00820068 (-)
  used my_allocator to deallocate at address 0080FB28 (-)
  used my_allocator to deallocate at address 0080C728 (-)
  used my_allocator to deallocate at address 0080C6F0 (-)
  used my_allocator to deallocate at address 0080AC78 (-)
  used my_allocator to deallocate at address 0080AC40 (-)
  used my_allocator to deallocate at address 0080AC08 (-)
  used my_allocator to deallocate at address 0080ABD0 (-)

Sie können sehen, dass RWTValDist normal erstellt wird und 100 Elemente eingefügt werden, wenn kein benutzerdefinierter Allokator verwendet wird. Wenn eine Liste mit my_allocator instanziiert wird, wird die Instanz von my_allocator für acht Zuweisungen und Freigaben von Heap-Speicher verwendet.

Je suppose que tu aimes

Origine blog.csdn.net/FYZDMMCpp/article/details/119974214
conseillé
Classement