Welche Sprachfeatures sollte man vermeiden?



  • @SeppJ sagte in Welche Sprachfeatures sollte man vermeiden?:

    • inline -> WTF? Eines der wichtigsten Sprachfeatures, ohne das man kaum auskommt. Dir ist klar, dass Funktionen, die in der Klassendefinition definiert werden, automatisch inline sind und dass das ungeheuer wichtig ist?

    Nein, ist mir nicht klar, danke für den Hinweis.
    Zum Inline dennoch:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1604r0.html



  • @Mond sagte in Welche Sprachfeatures sollte man vermeiden?:

    @SeppJ sagte in Welche Sprachfeatures sollte man vermeiden?:

    • inline -> WTF? Eines der wichtigsten Sprachfeatures, ohne das man kaum auskommt. Dir ist klar, dass Funktionen, die in der Klassendefinition definiert werden, automatisch inline sind und dass das ungeheuer wichtig ist?

    Nein, ist mir nicht klar, danke für den Hinweis.
    Zum Inline dennoch:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1604r0.html

    Da steht nicht, dass du inline vermeiden sollst.



  • @Mond
    Du hast goto vergessen. Ein Mittel was man heutzutage überhaupt nicht mehr benötigt, aber manchmal noch sieht und Spagetti-Code vom Feinsten produziert!



  • @Quiche-Lorraine sagte in Welche Sprachfeatures sollte man vermeiden?:

    Du hast goto vergessen. Ein Mittel was man heutzutage überhaupt nicht mehr benötigt

    Ausser in C - dort ist findet man es meistens in einer sinnvollen Anwendung: diesen "handgeschriebenen Destruktoren" am Funktionsende... goto cleanup, goto fail. Braucht man in C++ aber wirklich nicht mehr. Ausser vielleicht diesem Ding, wenn man aus mehrfach verschachtelten Schleifen herausspringen will - sowas löse ich aber meist mit return.



  • @Mond sagte in Welche Sprachfeatures sollte man vermeiden?:

    • Functors (besser Lamda benutzen)

    Das macht keinen Sinn. Labdas sind praktisch functors.



  • @SeppJ sagte in Welche Sprachfeatures sollte man vermeiden?:

    • friend -> eigentlich legitimes Mittel, wird aber fast immer nur aus Faulheit, Unwissen, oder mangelhaftem Design missbraucht. Wenn gut eingesetzt, dann spricht nichts dagegen. Da es insgesamt sowieso wenig genutzt wird, ist es sicher auch nicht so wichtig, groß darüber zu diskutieren. Wenn man doch viel friend in seinem Code hat, ist das ein Code Smell, denn man fällt dann fast sicher in die Kategorie Faulheit, Unwissen, mangelhaftes Design.

    Das ist der einzig sinnvolle Weg, um Operatoren wie operator* für z.B. Matrixklassen zu definieren. Wenn man sie nicht friend deklariert, dann braucht man ein Interface in der Klasse, die diese Operation nach außen zur Verfügung stellt, und dann trotzdem den externen freien operator*, weil sonst die Typpromotion im Kontext dieser Klasse nicht funktioniert.



  • @john-0 sagte in Welche Sprachfeatures sollte man vermeiden?:

    Das ist der einzig sinnvolle Weg, um Operatoren wie operator* für z.B. Matrixklassen zu definieren. Wenn man sie nicht friend deklariert, dann braucht man ein Interface in der Klasse, die diese Operation nach außen zur Verfügung stellt, und dann trotzdem den externen freien operator*, weil sonst die Typpromotion im Kontext dieser Klasse nicht funktioniert.

    Das kann ich nicht ganz nachvollziehen. Mein freier Multiplikationsoperator greift via public: T& operator(i, j) auf die Elemente zu und für besondere (z.B. SIMD-) Optimierungen stellt die Matrix-Klasse auch noch eine Member-Funktion public: T* Matrix::elements() zur Verfügung, wenn man linearen Zugriff auf den Speicher benötigt. friendist hier auch eine Lösung, aber sicher nicht die "einzig sinnvolle".



  • @SeppJ sagte in Welche Sprachfeatures sollte man vermeiden?:

    alte enums -> Fallen in die Richtung von rohen Zeigern, aber mit weniger praktischen Problemen, und allgemein geringer verbreiteter Nutzung. Aber eigentlich gibt es keinen legitimen Grund, sie noch zu nutzen.

    Naja was ist, wenn du das enum als Bitmaske verwenden möchtest, dann müsstest du vorher noch jeden einzelnen Operator dafür definieren und das dann auch noch pro Typ.

    Desöfteren benutze ich auch ein plain old enum innerhalb eines Klassen-Scopes. Somit ist eine Namenskollision gelindert und man kann sie gleich wie richtig nette und hundsgewöhnliche Integer behandeln.



  • @Finnegan sagte in Welche Sprachfeatures sollte man vermeiden?:

    Das kann ich nicht ganz nachvollziehen. Mein freier Multiplikationsoperator greift via public: T& operator(i, j) auf die Elemente zu und für besondere (z.B. SIMD-) Optimierungen stellt die Matrix-Klasse auch noch eine Member-Funktion public: T* Matrix::elements() zur Verfügung, wenn man linearen Zugriff auf den Speicher benötigt. friendist hier auch eine Lösung, aber sicher nicht die "einzig sinnvolle".

    Man will solche Details wie die interne Datenstruktur gar nicht nach außen sichtbar machen. Das ist ein internes Detail. Dazu braucht man für eine sinnvolle Implementation auch noch mehr Informationen als den reinen rohen Zeiger auf das Feld. Wie sind die Dimensionen, wie sind die Daten gespeichert (row-major- oder column-major-order), gibt es eine leading dimension, packed vs. nonpacked, … . Diese Dinge braucht man spätestens dann, wenn man z.B. eine hochoptimierte Version der BLAS S/D/C/ZGEMM routine anstatt der selbsgeschriebenen Routine nutzen will/muss.



  • @john-0 sagte in Welche Sprachfeatures sollte man vermeiden?:

    @Finnegan sagte in Welche Sprachfeatures sollte man vermeiden?:

    Das kann ich nicht ganz nachvollziehen. Mein freier Multiplikationsoperator greift via public: T& operator(i, j) auf die Elemente zu und für besondere (z.B. SIMD-) Optimierungen stellt die Matrix-Klasse auch noch eine Member-Funktion public: T* Matrix::elements() zur Verfügung, wenn man linearen Zugriff auf den Speicher benötigt. friendist hier auch eine Lösung, aber sicher nicht die "einzig sinnvolle".

    Man will solche Details wie die interne Datenstruktur gar nicht nach außen sichtbar machen. Das ist ein internes Detail. Dazu braucht man für eine sinnvolle Implementation auch noch mehr Informationen als den reinen rohen Zeiger auf das Feld. Wie sind die Dimensionen, wie sind die Daten gespeichert (row-major- oder column-major-order), gibt es eine leading dimension, packed vs. nonpacked,

    Ja, ich verstehe den Gedanken dahinter, ich habe da bei meiner Matrix-Klasse eine anderes Designziel: Ich sehe diese vornehmlich als ein mathematisches Array wie einen std::vector, der ja auch mit v.data() einen direkten Zugriff auf seine Daten erlaubt. Bei mir sind sogar matrix.element_order() (Row/Column-Major) und andere public-Member-Funktionen. Diese nicht-mathematischen Interna sollen auch nicht vor dem Anwender versteckt werden, da die Bibliothek keine abgeschlosene Einheit bildet, sondern vornehmlich mit anderen Bibliotheken und Grafik-APIs interagieren soll.

    Es handelt sich um eine Matrix-Klasse für statische Matrizen fester Größe für die Grafikprogrammierung (analog zu std::array). Matrizen und Arrays dieser Matrizen sollen hier unmodifiziert z.B. an OpenGL/Direct3D/Vulkan, Physik-Engines oder irgendwelche Bibliotheken für Grafik- und Geometriealgorithmen weitergereicht werden. Dafür ist es hier auch für den Anwender wichtig zu wissen, wie die Daten intern organisiert sind und dass er auf diese auch direkt zugreifen kann (z.B. ein std::vector<Matrix>::data() per API-Call direkt in den GPU-Speicher pumpen) .

    Nichts gegen friend - das ist sicher eine gute Lösung für deinen Anwendungsfall. Es ist nur eben nicht die "einzig sinnvolle" für eine Matrixklasse. Das hängt eben auch stark vom Anwendungsgebiet und den Designzielen ab.


Log in to reply