Warum hat C++ kein restrict keyword?



  • Hallo,

    ja Frage steht im Titel. Eines der wichtigen Argumente die man pro C++ immer wieder hört ist ja die Performance. Auch lese ich immer wieder mal von Zero-Cost Abstraction, Performance scheint also ziemlich wichtig zu sein.

    Warum gibt es also trotzdem (immer noch) kein restrict Schlüsselwort in C++ um z.B. bei manchen numerischen Algorithmen noch Geschwindigkeit herausholen zu können? In C gibts das ja schon länger.

    Gibt es dafür einen speziellen Grund oder ist das noch in Planung?

    (Ich weiß dass viele Compiler das abseits des Standards anbieten, aber das zählt mMn nicht)


  • Mod

    Ich verweise mal auf diese Anekdote von Herb Sutter:

    https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-and-c99/ schrieb:

    Visual C++ also partly supports some C99 language features under a slightly different syntax and possibly with slightly different semantics. Notably, we support __restrict – we did (and could again) consider allowing the standard C99 spelling restrict here for this feature, but please understand that this is not as simple as it looks. Not only the VC++ team, but also the ISO C++ standards committee, considered adding restrict to VC++ and ISO C++, respectively. Although it was specifically suggested for ISO C++11, it was rejected, in part because it’s not always obvious how it extends to C++ code because C++ is a larger language with more options and we would want to make sure the feature works correctly across the entire language.

    Außerdem mache ich darauf aufmerksam, dass restrict in C wesentlich dringender benötigt wurde, da es dort Alltag ist, dass man über void* und ähnliches auf Daten zugreift, während man in C++ normalerweise andere Mechanismen bevorzugt, bei denen klar ist (bzw. es vom Standard einfach so definiert wird), dass kein Aliasing vorliegt.


  • Mod

    z.B. bei manchen numerischen Algorithmen noch Geschwindigkeit herausholen zu können?

    Wie das?



  • Arcoth schrieb:

    z.B. bei manchen numerischen Algorithmen noch Geschwindigkeit herausholen zu können?

    Wie das?

    https://www.c-plusplus.net/forum/319543 + https://www.c-plusplus.net/forum/319553


  • Mod

    Restrict++ schrieb:

    Arcoth schrieb:

    z.B. bei manchen numerischen Algorithmen noch Geschwindigkeit herausholen zu können?

    Wie das?

    https://www.c-plusplus.net/forum/319543 + https://www.c-plusplus.net/forum/319553

    Super. Du bringst also genau Beispiele, wo jemand C mit cout als C++ verkauft hat. Das ist doch gerade das Anti-Beispiel, wieso man restrict in C++ nicht nötig hat, in C aber schon. Das wird in den gelinkten Threads auch erklärt, wenn du sie liest.



  • Und in einem der Threads wird dann auch von mir erklärt warum man doch restrict in C++ brauchen könnte. Weil sich blind auf "Inlining richtet mir alles" zu verlassen halt ein bisschen blauäugig ist.


  • Mod

    hustbaer schrieb:

    Und in einem der Threads wird dann auch von mir erklärt warum man doch restrict in C++ brauchen könnte. Weil sich blind auf "Inlining richtet mir alles" zu verlassen halt ein bisschen blauäugig ist.

    Ich revidiere zu "Warum man restrict in C++ nicht dringend nötig hat".



  • Also ich habe nochmal ein bisschen über das Thema nachgedacht...

    SeppJ schrieb:

    Außerdem mache ich darauf aufmerksam, dass restrict in C wesentlich dringender benötigt wurde, da es dort Alltag ist, dass man über void* und ähnliches auf Daten zugreift, während man in C++ normalerweise andere Mechanismen bevorzugt, bei denen klar ist (bzw. es vom Standard einfach so definiert wird), dass kein Aliasing vorliegt.

    Ich bin mir noch nicht sicher ob ich alles richtig verstanden habe. Aber wenn ich mir mal folgendes Beispiel nehme:

    #include <iostream>
    
    struct BigInt { int value; };
    
    void add(BigInt const &left, BigInt const &right, BigInt &result)
    {
        result.value = 0; // Ändert potentiell left und/oder right
        result.value = left.value + right.value;
    }
    
    int main()
    {
        BigInt i{ 2 };
        add(i, i, i);
        std::cout << i.value << "\n"; // Output: 0
    }
    

    Dann ist das eine ziemlich gebräuchliche Art in C++ eine Funktion zu schreiben, bei der aber doch gerade Aliasing auftritt, oder nicht?



  • happystudent schrieb:

    #include <iostream>
    
    struct BigInt { int value; };
    
    void add(BigInt const &left, BigInt const &right, BigInt &result)
    {
        result.value = 0; // Ändert potentiell left und/oder right
        result.value = left.value + right.value;
    }
    
    int main()
    {
        BigInt i{ 2 };
        add(i, i, i);
        std::cout << i.value << "\n"; // Output: 0
    }
    

    Dann ist das eine ziemlich gebräuchliche Art in C++ eine Funktion zu schreiben, bei der aber doch gerade Aliasing auftritt, oder nicht?

    Ja klar. Nur da tritt ja genau Aliasing auf, d.h. restrict würde nix helfen, weil man es hier gar nicht anwenden dürfte. Bzw. der add Aufruf mit i, i, i wäre mit restrict einfach falsch.

    restrict würde nur helfen, wenn eben kein Aliasing auftritt. Wie wenn man die von dir gezeigte Funktion mit i, j, k aufrufen würde.

    Wenn der Compiler die Funktion add in so einem i, j, k Fall dann inline erweitert, dann kann er sehen dass es eben kein Aliasing gibt, und kann entsprechend frei optimieren.
    Und da die üblichen C++ Compiler mittlerweile recht gut im inlinen sind (und in C++ auch viel mit Templates gemacht wird, wobei der Code dann üblicherweise sowieso in jeder Übersetzungseinheit vorliegt, inlining also super-einfach wird)...

    Doof wird es halt u.A. wenn man add in eine DLL auslagern möchte. Oder eine Funktion die etwas mehr macht, und daher viel dringenderen Bedarf hat möglichst gut optimiert zu werden. Bzw. wenn die Funktion ausreichend gross ist, und ausreichend oft aufgerufen wird, so dass der Compiler meint sie wäre gerade ein super Kandidat für "hier ist stop mit Inlining".



  • hustbaer schrieb:

    Doof wird es halt u.A. wenn man add in eine DLL auslagern möchte. Oder eine Funktion die etwas mehr macht, und daher viel dringenderen Bedarf hat möglichst gut optimiert zu werden. Bzw. wenn die Funktion ausreichend gross ist, und ausreichend oft aufgerufen wird, so dass der Compiler meint sie wäre gerade ein super Kandidat für "hier ist stop mit Inlining".

    Also ich kann ja hier den Vorteil durchaus sehen, aber wie oft kommt sowas real überhaupt vor?

    Wären solche hoch optimierten Funktionen nicht unterm Strich ohnehin ein Fall für von Hand mit Assembler selber machen + Eintrag in der Doku das der Aufruf mit der selben Variable in verschiedenen Slots nicht gültig ist?



  • Xebov schrieb:

    Also ich kann ja hier den Vorteil durchaus sehen, aber wie oft kommt sowas real überhaupt vor?

    Ja. Pfuh. Keine Ahnung 😃
    Und natürlich bleibt oft auch die Möglichkeit die DLL mit nem konformen C Compiler übersetzen zu lassen, wo man restrict dann hat. Oder Compiler-Extensions ala __restrict zu verwenden. Trotzdem wäre es praktisch.

    Genau das meint SeppJ denke ich auch wenn er schreibt 'Ich revidiere zu "Warum man restrict in C++ nicht dringend nötig hat"'.

    Ich behaupte ja auch nicht dass ich sehnsüchtig auf restrict warte weil es ach so wichtig ist. Ich behaupte nur dass es auch in C++ nicht wertlos wäre. Man könnte es hin und wieder schon brauchen.

    Xebov schrieb:

    Wären solche hoch optimierten Funktionen nicht unterm Strich ohnehin ein Fall für von Hand mit Assembler selber machen + Eintrag in der Doku das der Aufruf mit der selben Variable in verschiedenen Slots nicht gültig ist?

    Der Vorteil bei "eingebautem" restrict Keyword wäre dass der Compiler warnen kann wenn er sieht dass restrict beim Aufruf verletzt wird. (Bzw. u.U. sogar nen Fehler ausgeben, wenn er sicher sein kann dass es keinen Pfad geben kann wo restrict nicht verletzt wird.)
    U.U. könnte der Compiler sogar in DEBUG Builds Runtime-Checks einbauen die sicherstellen dass restrict nicht verletzt wird.

    Und was handoptimierten Assemblercode angeht...
    Neh. Sehe ich anders 🙂 Handoptimierter Assemblercode ist oft langsamer als das was ein guter Compiler ausspuckt. Klar, theoretisch kann man mit handoptimiertem Assemblercode immer zumindest gleich schnell sein. Aber in der Praxis schafft man es oft nicht. Bzw. zahlt es sich einfach viel zu selten aus die Zeit zu investieren die man investieren müsste.
    In Compiler wird nicht umsonst viel viel Zeit investiert damit die möglichst optimalen Code generieren.

    Allerdings bleibt wie ich oben schon geschrieben habe die Möglichkeit es in C zu schreiben und dann aus C++ aufzurufen. Das ist immer noch lästig, aber zumindest nicht SO schlimm viel Aufwand.



  • hustbaer schrieb:

    Der Vorteil bei "eingebautem" restrict Keyword wäre dass der Compiler warnen kann wenn er sieht dass restrict beim Aufruf verletzt wird. (Bzw. u.U. sogar nen Fehler ausgeben, wenn er sicher sein kann dass es keinen Pfad geben kann wo restrict nicht verletzt wird.)
    U.U. könnte der Compiler sogar in DEBUG Builds Runtime-Checks einbauen die sicherstellen dass restrict nicht verletzt wird.

    Das ist natürlich ein gutes Argument, allerdings auch ein ordentlicher Aufwand für die Compilerhersteller.




Log in to reply