Kann der Compiler das optimieren?



  • wie du selbst schon angesprochen hast, könnte man die WinAPI in C++ auch ganz anders schreiben. nur war ich mir nicht mehr sicher, wie sehr ich darauf eingehen sollte, weil man nicht genau erkennen kann, an welcher stelle der sarkasmus beginnt 😉

    btw. häng an die ~20 vielleicht noch eine null dran, und für jeden eigenen typ auch noch mal soviele (für alle kombinationen) - variadic templates oder gar nicht erst in die versuchung kommen, sondern gleich die typsicheren streams verwenden.



  • queer_boy schrieb:

    btw. häng an die ~20 vielleicht noch eine null dran, und für jeden eigenen typ auch noch mal soviele (für alle kombinationen)

    Ungeachtet der Ernsthaftigkeit des Vorschlages: weshalb für jeden eigenen Typ nochmal so viele? Für 0-19 Parameter reichen doch 20 Überladungen, oder?

    queer_boy schrieb:

    variadic templates oder gar nicht erst in die versuchung kommen, sondern gleich die typsicheren streams verwenden.

    Was macht denn boost::function?



  • audacia schrieb:

    queer_boy schrieb:

    variadic templates oder gar nicht erst in die versuchung kommen, sondern gleich die typsicheren streams verwenden.

    Was macht denn boost::function?

    Was hat das mit 'boost::function' zu tun? Die sind doch typensicher.

    Btw, zur Tupel-Rückgabe: natürlich ist die WinAPI eingeschränkt, da sie eine sehr typenbeschränkte Schnittstelle darstellt, um möglichst vielseitig einsetzbar zu sein. Dass man auch heute noch größtenteils an einer C-Schnittstelle für jegliches Interop hängt, ist natürlich extrem schade, weil es doch die Möglichkeiten extrem beengt.

    Die WinAPI ist ja geradezu das Paradebeispiel, wie man es nicht machen sollte. Sowas passiert eben, wenn man versucht, in C OOP zu programmieren.



  • Konrad Rudolph schrieb:

    Was hat das mit 'boost::function' zu tun? Die sind doch typensicher.

    boost::function ist nicht mittels Variadic Templates, sondern über die Mehrfachüberladung implementiert, vor der queer_boy mich so dringend warnte.

    Konrad Rudolph schrieb:

    Btw, zur Tupel-Rückgabe: natürlich ist die WinAPI eingeschränkt, da sie eine sehr typenbeschränkte Schnittstelle darstellt, um möglichst vielseitig einsetzbar zu sein.

    Vielleicht hätte ich den Sarkasmus noch deutlicher durchblicken lassen sollen.
    Hältst du meine ReadFile-Versionen im Ernst für in irgendeiner Weise praxistauglich?

    Konrad Rudolph schrieb:

    Dass man auch heute noch größtenteils an einer C-Schnittstelle für jegliches Interop hängt, ist natürlich extrem schade, weil es doch die Möglichkeiten extrem beengt.

    Die WinAPI ist ja geradezu das Paradebeispiel, wie man es nicht machen sollte. Sowas passiert eben, wenn man versucht, in C OOP zu programmieren.

    Das sehe ich anders. Ein Betriebssystem wie Windows _sollte_ IMHO eine C-Schnittstelle haben und nicht eine, die es auf eine der Hochsprachen und ein ABI beschränkt - es sei denn, es ist für mehrere Sprachen entworfen wie das .NET-Framework, und selbst das ist ja in C++ nur mit einer gewaltigen Verrenkung namens C++/CLI verwendbar.



  • audacia schrieb:

    Konrad Rudolph schrieb:

    Was hat das mit 'boost::function' zu tun? Die sind doch typensicher.

    boost::function ist nicht mittels Variadic Templates, sondern über die Mehrfachüberladung implementiert, vor der queer_boy mich so dringend warnte.

    Ja, weil es variadic templates eben noch nicht gibt.

    Konrad Rudolph schrieb:

    Btw, zur Tupel-Rückgabe: natürlich ist die WinAPI eingeschränkt, da sie eine sehr typenbeschränkte Schnittstelle darstellt, um möglichst vielseitig einsetzbar zu sein.

    Vielleicht hätte ich den Sarkasmus noch deutlicher durchblicken lassen sollen.
    Hältst du meine ReadFile-Versionen im Ernst für in irgendeiner Weise praxistauglich?

    Nein, die Version ist natürlich schlecht und man würde die ganz anders implementieren. Aber ich halte trotzdem keine Version mit Ausgabe-Parametern für sinnvoll. Übrigens benutzt die STL Mechanismen, die recht ähnlich sind, z.B. die 'insert'-Methode von Containern.

    Konrad Rudolph schrieb:

    Dass man auch heute noch größtenteils an einer C-Schnittstelle für jegliches Interop hängt, ist natürlich extrem schade, weil es doch die Möglichkeiten extrem beengt.

    Die WinAPI ist ja geradezu das Paradebeispiel, wie man es nicht machen sollte. Sowas passiert eben, wenn man versucht, in C OOP zu programmieren.

    Das sehe ich anders. Ein Betriebssystem wie Windows _sollte_ IMHO eine C-Schnittstelle haben und nicht eine, die es auf eine der Hochsprachen und ein ABI beschränkt - es sei denn, es ist für mehrere Sprachen entworfen wie das .NET-Framework, und selbst das ist ja in C++ nur mit einer gewaltigen Verrenkung namens C++/CLI verwendbar.

    Ich habe ja auch nicht gesagt, dass man es besser machen könnte. Die WinAPI ist gewissermaßen das kleinste Übel. Trotzdem ist sie schlimm.



  • Konrad Rudolph schrieb:

    Ja, weil es variadic templates eben noch nicht gibt.

    Genau darum sehe ich im Gegensatz zu queer_boy auch keine Verwerflichkeit darin, sich, solange das der Fall ist, dieses Hilfsmittels zu bedienen.

    Konrad Rudolph schrieb:

    Aber ich halte trotzdem keine Version mit Ausgabe-Parametern für sinnvoll. Übrigens benutzt die STL Mechanismen, die recht ähnlich sind, z.B. die 'insert'-Methode von Containern.

    Du bist dir der Einschränkung, der man sich unterzieht, wenn man nicht direkt in einen Puffer lesen lassen kann, weil man den als Parameter übergeben müßte, bewußt?

    Konrad Rudolph schrieb:

    Ich habe ja auch nicht gesagt, dass man es besser machen könnte. Die WinAPI ist gewissermaßen das kleinste Übel. Trotzdem ist sie schlimm.

    Achso, du meinst so ähnlich wie bei Churchill und der Demokratie? Dann kann ich dir natürlich beipflichten. 😉



  • Konrad Rudolph schrieb:

    Learning Java: Better never than late.

    Dabei kannst du in Java einfach beliebig Pointer auf Klassen zurückgeben und der GC kümmert sich um den Rest. Past doch besser zu deinen Wünschen als C++.



  • audacia schrieb:

    Konrad Rudolph schrieb:

    Aber ich halte trotzdem keine Version mit Ausgabe-Parametern für sinnvoll. Übrigens benutzt die STL Mechanismen, die recht ähnlich sind, z.B. die 'insert'-Methode von Containern.

    Du bist dir der Einschränkung, der man sich unterzieht, wenn man nicht direkt in einen Puffer lesen lassen kann, weil man den als Parameter übergeben müßte, bewußt?

    Hmm, nein, ehrlich gesagt gerade nicht. Kann sein, dass ich auf dem Schlauch stehe aber was hindert einen daran, einen Proxy zurückzugeben, der operator= überlädt und erst zum Zeitpunkt der Zuweisung das Auslesen übernimmt?

    Konrad Rudolph schrieb:

    Ich habe ja auch nicht gesagt, dass man es besser machen könnte. Die WinAPI ist gewissermaßen das kleinste Übel. Trotzdem ist sie schlimm.

    Achso, du meinst so ähnlich wie bei Churchill und der Demokratie?

    Jupp, genauso. Das Leben [eines Programmierers] besteht aus faulen Kompromissen. 😉

    haha. schrieb:

    Konrad Rudolph schrieb:

    Learning Java: Better never than late.

    Dabei kannst du in Java einfach beliebig Pointer auf Klassen zurückgeben und der GC kümmert sich um den Rest. Past doch besser zu deinen Wünschen als C++.

    Ich halte mich da ganz nach Stepanov. C++ mag fehlerbehaftet sein (ich *hasse* diese Syntax), ist aber trotzdem brillant. Java ist einfach uninteressant. „… it has no intellectual value whatsoever.“ Natürlich muss man immer vorsichtig sein, wenn man einen Polemiker wie Stepanov zitiert, aber konziser kann man es einfach nicht sagen. (Für die anderen: ich halte jetzt meinen Mund. Das wird kein Sprachen-Krieg-Thread.)



  • Konrad Rudolph schrieb:

    Ich halte mich da ganz nach Stepanov. C++ mag fehlerbehaftet sein (ich *hasse* diese Syntax), ist aber trotzdem brillant.

    naja, sagen wir mal C++ spricht den spieltrieb mancher leute an. brilliant ist aber was anderes.
    🙂



  • audacia schrieb:

    Konrad Rudolph schrieb:

    Ja, weil es variadic templates eben noch nicht gibt.

    Genau darum sehe ich im Gegensatz zu queer_boy auch keine Verwerflichkeit darin, sich, solange das der Fall ist, dieses Hilfsmittels zu bedienen.

    diese diskussion drehte sich ja zunächst darum, ob snprintf eine gute alternative zu stringstreams ist. daraufhin meinte jemand, das stringstreams typensicher sind, ein großer vorteil - und dann wurde die gesamt diskussion sehr hypothetisch. der punkt war nicht der, dass funktionsüberladungen hässlich sind, sondern dass es stringstreams gibt. mehr wollte ich nicht sagen, glaube mir 😉

    oder in deinen worten: es ist doch nicht verwerflich, sich dieses hilfsmittels zu bedienen.

    aber damit klinke ich mich jetzt hier aus.



  • Konrad Rudolph schrieb:

    Hmm, nein, ehrlich gesagt gerade nicht. Kann sein, dass ich auf dem Schlauch stehe aber was hindert einen daran, einen Proxy zurückzugeben, der operator= überlädt und erst zum Zeitpunkt der Zuweisung das Auslesen übernimmt?

    Gar nicht ungeschickt soweit.
    Zufällig hatte ich gerade Lust dazu:

    #include <windows.h>
    #include <vector>
    #include <iterator>
    
    class File
    {
    private:
        HANDLE hFile;
        DWORD  pos;
    
    public:
        template <typename T>
            class FilePart
        {
            friend class File;
    
        private:
            HANDLE file;
            DWORD pos;
            DWORD cnt;
    
            FilePart (HANDLE hFile, DWORD dwPos, DWORD dwCnt)
             : file (hFile), pos (dwPos), cnt (dwCnt)
            {}
    
        public:
            class const_iterator;
            friend class const_iterator;
    
            class const_iterator
            {
                friend class FilePart;
    
            private:
                const FilePart* fp;
                DWORD           pos;
    
                const_iterator (const FilePart* filepart, DWORD dwPos)
                 : fp (filepart), pos (dwPos)
                {}
    
            public:
                typedef int difference_type;
                typedef T   value_type;
                typedef T*  pointer;
                typedef T&  reference;
                typedef std::input_iterator_tag iterator_category;
    
                const_iterator& operator ++ (void)
                { pos += sizeof (T); }
                const_iterator& operator -- (void)
                { pos -= sizeof (T); }
                const_iterator& operator ++ (int)
                {
                    const_iterator rv (*this);
                    pos += sizeof (T);
                    return rv;
                }
                const_iterator& operator -- (int)
                {
                    const_iterator rv (*this);
                    pos -= sizeof (T);
                    return rv;
                }
    
                bool operator == (const_iterator& rhs)
                { return (fp == rhs.fp) && (pos == rhs.pos); }
                bool operator != (const_iterator& rhs)
                { return (fp != rhs.fp) || (pos != rhs.pos); }
    
                T operator * (void) const
                {
                    T rv;
                    DWORD nobr;
                    OVERLAPPED ov;
    
                    ZeroMemory (&ov, sizeof (ov));
                    ov.Offset = pos;
                    ReadFile (fp->file, &rv, sizeof (T), &nobr, &ov);
                    return rv;
                }
                // T* operator -> (void) const wird aus naheliegenden Gründen
                // nicht implementiert
            };
    
            const_iterator begin (void) const
            { return const_iterator (this, pos); }
            const_iterator end (void) const
            { return const_iterator (this, pos + cnt * sizeof (T)); }
        };
    
        // ...
    
        File (const char* lpFilename, DWORD dwAccess = GENERIC_READ,
            DWORD dwShareMode = FILE_SHARE_READ,
            DWORD dwCreationDisposition = OPEN_ALWAYS)
         : pos (0)
        {
            hFile = CreateFile (lpFilename, dwAccess, dwShareMode, NULL,
                dwCreationDisposition, 0, NULL);
        }
    
        template <typename T>
            FilePart <T> read (DWORD dwCnt)
        {
            union u { T t; }; // schlägt fehl, wenn T nicht trivial ist
    
            DWORD opos = pos;
            // evtl. Bereichsüberprüfungen
            pos += dwCnt * sizeof (T);
            return FilePart <T> (hFile, opos, dwCnt);
        }
    };
    
    int main (void)
    {
        File file ("myFile.bin");
        std::vector <int> v;
    
        File::FilePart <int> fp = file.read <int> (42);
        v.insert (v.begin (), fp.begin (), fp.end ());
    
        return 0;
    }
    

    Wirklich wunderschön, das gebe ich zu.

    Nur:

    #include <windows.h>
    #include <vector>
    
    int main (void)
    {
        std::vector <int> v;
        HANDLE hFile;
        DWORD nobr;
    
        v.resize (42);
        hFile = CreateFile (lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_ALWAYS, 0, NULL);
        ReadFile (hFile, &*(v.begin ()), sizeof (T) * 42, &nobr, NULL);
    }
    

    Irgendwie ist das hier (bzw. eine etwas mehr gekapselte, exceptionsichere Version hiervon) dann doch zu bevorzugen, meinst du nicht? Schon weil ReadFile 41-mal weniger ausgeführt werden muß 😉 Und auch sonst ist das ein bißchen wartungsfreundlicher.

    Konrad Rudolph schrieb:

    Das Leben [eines Programmierers] besteht aus faulen Kompromissen. 😉

    ... und großen Momenten 😉


Anmelden zum Antworten