Allokatoren und die NUMA-Problematik



  • @hustbaer sagte in Allokatoren und die NUMA-Problematik:

    Ich habe deine Frage beantwortet.

    Du bist der Meinung, Du hättest sie beantwortet. Das ist ein wesentlicher Unterschied. Meine Frage zielte darauf, ob man mit den für Container definierten Konstrukturen einen Container konstruieren kann, wenn T die geforderten Konzepte nicht unterstützt. Das ist offensichtlich nicht der Fall.

    Und was bitte sollen "unvollständige Typen (in Sinne der Container Definition)" sein?

    Es geht darum, ob ein T alle Konzepte unterstützt, die ein Container benötigt, um den vollen Funktionsumfang des Containers auch unterstützen zu können. Bei dem hier besprochenem ist das offensichtlich nicht der Fall. Dazu erfordert Container<T>.emplace(p.args) bei vector und deque neben dem Konzept EmplaceConstructible auch noch MoveInsertable und MoveAssignable.

    Du erfindest hier Begriffe die es im Standard einfach nicht gibt. Was ein Element-Typ für einen Container können muss ist abhängig davon was man mit dem Container machen möchte. So zu tun als müssten immer alle Typen alles können weil ...

    Der wesentliche Punkt ist, wenn ein T ein Konzept, welches für eine bestimmte Funktionalität des Containers notwendig ist, nicht unterstützt, lässt sich der Programmcode nicht übersetzen. Außer wenn wir über Allocator::POCS::value==std::false_type reden, dann geht das auf einmal doch. Es gibt nun einmal keinerlei sinnvollen Grund, weshalb das noch compilieren soll und UB ergibt. D.h. wenn man Allocator::POCS::value==std::false_type hat, dann darf man eben kein Container<T,Allocator<T>>.swap nutzen. Das wäre mit den neuen Möglichkeiten von C++17 auch kein Problem, und wird an anderer Stelle auch getestet.

    Das ist das Niveau des Standards. Finde ich auch nicht gut, aber ich verstehe jetzt wieso es so gemacht wurde. Du willst es anscheinend nicht verstehen. Vermutlich damit du dich schlau fühlen und die Standard-Leute für doof halten kannst.

    Vergessen wir bitte nicht den Ausgangspunkt. Am Anfang stand die Frage, ob es möglich sei eine Matrixklasse mit vector als low level Speicher zu verwenden. Wie man nun sieht, bekommt man Probleme, wenn man einen Allokator nutzt, der POCS als false_type definiert. Gerade an diesem Punkt wird eine eigene Matrixklasse bei HPC aber interessant. Es geht nicht darum sich überlegen zu fühlen, sondern um konkrete Lösungsansätze für konkrete Probleme. Das Fazit daraus, es gibt auch weiterhin gute Gründe low level Speicherverwaltung zu machen, und auf vector mit einem speziellem Allokator zu verzichten. Man kann nun länger darüber diskutieren, ob man bei der angesprochenen Matrixklasse direkt low level Funktionen verwendet, oder ob man diese Klassee AllocatorAware schreibt. Das geht nämlich sehr wohl, so dass POCS trotzdem richtig ausgewertet wird und diese Klasse kein UB hat. Man hat dann nur nicht das O(1) Verhalten von Standard Containern bei swap.

    Ja, weiss ich. Mir ging es darum Gründe aufzuzeigen warum es mehr oder weniger Sinn macht dass das so definiert wurde. BTW: Ein weiterer Grund: selbst vor C++11 wurde von swap() schon garantiert dass die Adressen der Elemente nach swap() gleich bleiben. Und diese Garantie wollte man vermutlich nicht einfach so einschränken.

    Bei C++2003 war das auch kein Problem, weil es keine Allokatoren mit Zustand geben konnte. D.h. die Definition von Allokatoren und Container waren konsistent. Grundsätzlich spricht nichts dagegen dieses Verhalten unter den gleichen Umständen zu erhalten. Aber weshalb definiert man in den allocator_traits::POCS, wenn die Standard Library offensichtlich davon keinerlei Gebrauch macht? Nur zur Nutzung in eigenem Code? Das ist wirklich dünn.

    Wie, übersetzt nicht? Das Beispiel übersetzt wunderbar.

    Du hast ein Beispiel gebracht, dass das Konzept EmplaceConstructible fordert, und eine Klasse übergeben, die das erfüllt. Was passiert, wenn die Klasse nicht EmplaceConstructible ist?

    Da hätte man doch wenigstens in die Norm hineinschreiben können, dass das nicht übersetzen soll. Im Sinne von static_assert.

    Damit würde man allerdings valide Anwendungsfälle verhindern die jetzt möglich (und wohldefiniert) sind. Ob diese wichtig genug sind kann man natürlich hinterfragen.

    Nein, genau das würde nicht passieren. D.h. wenn man in Container<T>.swap()

    static_assert(std::allocator_traits<Allocator>::is_always_equal() ||
    		std::allocator_traits<Allocator>::propagate_on_container_swap(), "Container Swap is UB");
    

    einfügen würde. Wäre das Problem gelöst, und existierenden Code würde weiterhin genau so funktionieren wie man es bisher kannte. Nur würde der Versuch swapmit dem falschen Allokator zu verwenden vom Compiler abgefangen.



  • @john-0 Sorry, aber mir wirds echt zu blöd auf dein Geschwurbel weiter einzugehen.



  • @hustbaer sagte in Allokatoren und die NUMA-Problematik:

    @john-0 Sorry, aber mir wirds echt zu blöd auf dein Geschwurbel weiter einzugehen.

    Mit Verlaub, die Funktion emplace wurde erst mit C++2017 eingeführt. statefull allocators bereits mit C++2011. Deine ganze Argumentation funktioniert nicht. Wenn man denn nicht weiter diskutieren will, kann man das auch anders tun als sich über die Beiträge anderer dispektierlich zu äußern.