Warum sind std :: allocators nicht so beliebt? [geschlossen]

8

Mit den neuesten Trends zu C- und C ++ - Anwendungen und mit den neuesten, ich meine den letzten Jahren, hatte ich erwartet, dass std::allocators viel häufiger verwendet werden als es wirklich ist.

Moderne Anwendungen sind in der Regel Multithread-Anwendungen oder in Form von Parallelität und verwalten eine erhebliche Menge an Speicher, insbesondere in einigen Bereichen wie Spielen und Multimedia-Anwendungen. Daher steigen die üblichen hohen Kosten für die Zuweisung / Freigabe und wirken sich noch stärker auf die Leistung aus als bei alten Anwendungen.

Aber für das, was ich sehen kann, ist diese Art der Speicherverwaltung durch std::allocators nicht beliebt. Ich kann nicht einmal eine mir bekannte Bibliothek zählen, die eine Begründung für eine standardisierte Art der Speicherverwaltung verwendet.

Es gibt einen echten Grund, warum std::allocatornicht beliebt ist? Technische Gründe?

user2485710
quelle
2
weil es schwer zu bedienen ist?
Bryan Chen
4
@BryanChen was meinst du damit? Der Allokator ist normalerweise das zweite Argument in einem Standardcontainer. std::allocatorEr ist äußerst einfach zu verwenden.
user2485710
1
Fragen Sie sich, warum std::allocator(was im Grunde genommen ein Wrapper newund eine Platzierung ist new) nicht so häufig verwendet wird? Oder fragen Sie sich, warum das C ++ - Konzept von Allocatornicht weit verbreitet ist? Das sind zwei verschiedene Fragen.
Dave S
@ DaveS ähnelt eher der ersten Option, aber ich verstehe nicht, warum sie sich von der zweiten unterscheidet. Sie meinen etwas, das mit der Portabilität des Codes selbst zusammenhängt?
user2485710
1
@BryanChen kannst du zeigen, warum es schwer ist? Was sind die Fallstricke?
user2485710

Antworten:

13

Hier gibt es zwei Fragen:

1) Warum wird nicht std::allocatormehr verwendet?

Die kurze Antwort ist, weil für die meisten Anwendungen die Verwendung newund deleteausreichend ist.

Zunächst ein kurzer Überblick darüber, wofür das C ++ 11 Allocator-Konzept gedacht ist. Wenn Sie a ausführen, wird im Grunde genommen new Foosowohl Speicher zugewiesen als auch das Objekt in diesem Speicher erstellt.

Was aber, wenn Sie Speicher zuweisen und in zwei separaten Schritten konstruieren müssen? Das klassische Beispiel hierfür ist std::vector, dass Speicher zugewiesen werden kann, ohne ihn sofort zu initialisieren, aber dann die Elemente erstellt, wenn Sie sie dem Container hinzufügen. Der Zweck von std::allocatorbesteht darin, eine Schnittstelle bereitzustellen, um diese separaten Schritte auf einheitliche Weise auszuführen.

Für die meisten Benutzer ist diese Kontrollebene jedoch nicht erforderlich, da dies nur eine weitere Sache ist, die Sie beim Bereinigen Ihrer Ausnahmen beachten müssen.

2) Warum nutzen nicht mehr Dinge das C ++ - Konzept von Allocator?

Meistens ist die Notwendigkeit nicht da. Die einzigen Klassen, die sie verwenden, sind diejenigen, die ihren Benutzern mehr Kontrolle über die Quelle des von ihnen zugewiesenen Speichers geben möchten. Die Standardbibliothekscontainer sind so geschrieben, dass der Benutzer diese Entscheidungen treffen kann, wenn er dies wünscht. Standardmäßig wird jedoch der normale Allokator verwendet.

Dave S.
quelle
3
+1 für Punkt 1, was meiner Meinung nach der wahre Grund ist. Nicht "es ist schwer zu benutzen", was ich völlig ablehne, wenn ich viele Speicherzuordnungen für verschiedene Speicherpools geschrieben habe: Der Zuweiser ist recht einfach zu schreiben und nur eine schnittstellenkonforme Reihe von Methoden. Wie Sie den Speicher verwalten, liegt bei Ihnen, kann einfach oder schwierig sein (Chunking mit Koaleszenzmechanismen)
Marco A.
5

Die Popularität einer Sprache oder eines Bibliothekskonzepts steht in umgekehrter Korrelation mit der zugrunde liegenden Komplexität.

Das std::allocatorist ein Low-Level-Konzept und hat als solches potenzielle Fallstricke. Ein benutzerdefinierter Allokator im Voraus zu haben, wird wahrscheinlich als vorzeitige Optimierung eingestuft. Ähnlich wie bei anderen Low-Level-Konzepten wird es im Allgemeinen bevorzugt, das Arbeitszuweisungsmanagement an Bibliotheken (stdlib, boost) zu delegieren, es sei denn, der Aufwand für die Bearbeitung der Komplexität Ihrer eigenen Zuordnungen ist absolut gerechtfertigt.

Betrachten Sie Zeiger als nur ein unterstützendes Beispiel für diese These. Wir lieben Zeiger für ihren uneingeschränkten Zugriff auf Speicher und den Null-Overhead, aber in C ++ wissen wir besser, Scoped / Raii-Wrapper zu verwenden, um die Komplexität zu verwalten, das heißt, bis wir die Leistung explizit benötigen oder uns alle auf eine Semantik einigen können, die uns nicht gehört gut definierte Anwendungsfälle.

Wenn Sie einen std :: allocator verwenden, müssen Sie die ABI- und API-Kompatibilität sowie wunderbare Fragen wie das gewünschte Verhalten berücksichtigen, wenn der Code
std::vector<T,A1>().swap(std::vector<T,A2>())mit verschiedenen (und statusbehafteten!) A1Und A2Allokatoren zusammenarbeitet. Außerdem verwenden einige Container den Allokator nicht einmal so, wie Sie es beabsichtigt haben! Schauen Sie sich std::list<T,A>oder std::map<K,T,C,A>zum Beispiel an. Die natürliche Erwartung ist, dass der Allokator verwendet wird, um Objekte vom Typ Tfür eine Liste oder eine pair<const K,T>Karte zuzuweisen. In der Praxis fordert eine Standardbibliotheksimplementierung jedoch die Zuweisung einer Liste oder eines Kartenknotens an, und sogar die Größe des Knotens kann sein unterscheidet sich zwischen Release- und Debug-Builds. Benutzerdefinierte Allokatoren sind voller Kleinigkeiten, und die zusätzliche Komplexität und Detailgenauigkeit ist für die gängigsten Programmieraufgaben nicht erforderlich.

Mockinterface
quelle
Was ist der Aufwand für die Verwendung des RAII-Wrappers, std::unique_ptr<T>um Speicher zu besitzen, im Gegensatz dazu T *?
David Stone
@ DavidStone Wie Sie wahrscheinlich bereits gewusst haben (was eine Trickfrage ist), lautet die Antwort Null.
underscore_d
2

Ein Allokator ist eine Richtlinie, die von Abhängigkeiten in die Standardcontainer eingefügt wird. Es dient hauptsächlich dazu, dem Client-Code zu ermöglichen, die Zuordnungsrichtlinie von der Instanziierung in bereits implementierten Containern zu trennen .

Das Problem tritt auf, wenn Sie std :: container verwenden müssen und die Standardzuweisungsrichtlinie (wie von std :: allocator implementiert) nicht den Anforderungen Ihres Projekts entspricht (z. B. soll die std :: vector-Implementierung ausgelöst werden, wenn mehr Wenn mehr als 1024 Objekte zugewiesen sind, möchten Sie einen Speicherpool verwenden oder sicherstellen, dass alle Zuordnungen in einem bestimmten Speicherbereich vorab zugewiesen sind usw.).

Wenn Sie keinen anderen Allokator in die Container einfügen könnten, wäre es Ihnen in einigen Projekten untersagt, die std :: -Container insgesamt zu verwenden.

Um dies zu umgehen (und sicherzustellen, dass Sie die std :: -Container weiterhin verwenden können, wenn Sie komplexe Speicheranforderungen haben), ist der Allokator ein Vorlagenparameter für die Container.

Um Ihre Frage zu beantworten : Die meisten Benutzer verwenden keine std :: allocators, da sie beim Schreiben von Clientcode die volle Kontrolle über die Zuweisungen haben - sie müssen also keine Zuweisungsrichtlinie einfügen - und wenn sie Bibliothekscode verwenden, den std :: Allokator ist normalerweise genug.

utnapistim
quelle