Die Boost C++ Bibliotheken

Kapitel 2. Boost.PointerContainer

Die Bibliothek Boost.PointerContainer bietet für die Verwaltung dynamisch reservierter Objekte spezielle Container an. Verwenden Sie C++11, können Sie einen entsprechenden Container zum Beispiel mit std::vector<std::unique_ptr<int>> selbst erstellen. Die von Boost.PointerContainer angebotenen Container können jedoch zusätzlichen Komfort bieten.

Beispiel 2.1. boost::ptr_vector in Aktion
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>

int main()
{
  boost::ptr_vector<int> v;
  v.push_back(new int{1});
  v.push_back(new int{2});
  std::cout << v.back() << '\n';
}

Die Klasse boost::ptr_vector, die im Beispiel 2.1 verwendet wird und in der Headerdatei boost/ptr_container/ptr_vector.hpp definiert ist, funktioniert grundsätzlich genauso wie ein Container vom Typ std::vector<std::unique_ptr<int>>. Da boost::ptr_vector jedoch weiß, dass es dynamisch reservierte Objekte speichert, geben Methoden wie back() eine Referenz auf ein dynamisch reserviertes Objekt zurück und keinen Zeiger. Das Beispiel gibt entsprechend 2 auf die Standardausgabe aus.

Beispiel 2.2. boost::ptr_set mit intuitiv richtiger Sortierung
#include <boost/ptr_container/ptr_set.hpp>
#include <boost/ptr_container/indirect_fun.hpp>
#include <set>
#include <memory>
#include <functional>
#include <iostream>

int main()
{
  boost::ptr_set<int> s;
  s.insert(new int{2});
  s.insert(new int{1});
  std::cout << *s.begin() << '\n';

  std::set<std::unique_ptr<int>, boost::indirect_fun<std::less<int>>> v;
  v.insert(std::unique_ptr<int>(new int{2}));
  v.insert(std::unique_ptr<int>(new int{1}));
  std::cout << **v.begin() << '\n';
}

Beispiel 2.2 zeigt einen anderen Grund, warum es von Vorteil sein kann, einen spezialisierten Container zu verwenden. In diesem Beispiel werden dynamisch reservierte Variablen vom Typ int in einem boost::ptr_set und in einem std::set gespeichert. Für das std::set wird auf std::unique_ptr zugegriffen.

boost::ptr_set versteht automatisch, dass die Reihenfolge der Elemente von den gespeicherten int-Werten abhängt. std::set hingegen würde std::unique_ptr miteinander vergleichen – also Smartpointer und nicht die Variablen, auf die die Smartpointer zeigen. Damit die Sortierung im Beispiel 2.2 auch bei std::set auf den int-Werten basiert, muss angegeben werden, wie Vergleiche durchzuführen sind. Hierzu wird auf eine Klasse boost::indirect_fun zugegriffen, die aus Boost.PointerContainer stammt. Mit Hilfe dieser Klasse wird std::set mitgeteilt, dass die Sortierung nicht basierend auf den Smartpointern durchgeführt werden soll, sondern basierend auf den int-Variablen, auf die die Smartpointer zeigen. Wenn Sie das Beispiel ausführen, wird zweimal 1 ausgegeben.

Neben boost::ptr_vector und boost::ptr_set stehen weitere Container zur Verfügung, die auf die Verwaltung dynamisch reservierter Objekte spezialisiert sind. Dazu gehören boost::ptr_deque, boost::ptr_list, boost::ptr_map, boost::ptr_unordered_set und boost::ptr_unordered_map. Diese Container entsprechen den aus der Standardbibliothek bekannten Containern.

Beispiel 2.3. Inserter für Container von Boost.PointerContainer
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/ptr_container/ptr_inserter.hpp>
#include <array>
#include <algorithm>
#include <iostream>

int main()
{
  boost::ptr_vector<int> v;
  std::array<int, 3> a{{0, 1, 2}};
  std::copy(a.begin(), a.end(), boost::ptr_container::ptr_back_inserter(v));
  std::cout << v.size() << '\n';
}

Boost.PointerContainer bietet für seine Container Inserter an. Diese befinden sich im Namensraum boost::ptr_container und sind in der Headerdatei boost/ptr_container/ptr_inserter.hpp definiert.

Im Beispiel 2.3 wird auf die Funktion boost::ptr_container::ptr_back_inserter() zugegriffen, die einen Inserter vom Typ boost::ptr_container::ptr_back_insert_iterator erstellt. Dieser wird an std::copy() übergeben, um die Zahlen im Array a in den Vektor v zu kopieren. Da v ein Container vom Typ boost::ptr_vector ist, der Adressen von dynamisch reservierten int-Objekten erwartet, muss ein von Boost.PointerContainer angebotener Inserter verwendet werden. Diese erstellen eine Kopie mit new auf dem Heap und fügen die Adresse dem Container hinzu.

Neben boost::ptr_container::ptr_back_inserter() bietet Boost.PointerContainer die Funktionen boost::ptr_container::ptr_front_inserter() und boost::ptr_container::ptr_inserter(), um entsprechende Inserter zu erstellen.

Aufgabe

Entwickeln Sie ein Programm, in dem mehrere Instanzen einer Klasse animal mit den Eigenschaften name, legs und has_tail erstellt und in einem Container von Boost.PointerContainer gespeichert werden. Sortieren Sie den Container aufsteigend nach der Anzahl der Beine und schreiben Sie alle Elemente im Container in die Standardausgabe.