Vorteile von Inline-Funktionen in C ++?


254

Was sind die Vor- und Nachteile der Verwendung von Inline-Funktionen in C ++? Ich sehe, dass es nur die Leistung für den Code erhöht, den der Compiler ausgibt, aber mit den heute optimierten Compilern, schnellen CPUs, großem Speicher usw. (nicht wie im Jahr 1980 <wo Speicher knapp war und alles in 100 KB Speicher passen musste), was Vorteile haben sie heute wirklich?


48
Dies ist eine dieser Fragen, bei denen allgemeines Wissen falsch ist. Jeder hat mit der Standardantwort von Comp Sci geantwortet. (Inlining spart Funktionsaufrufkosten, erhöht jedoch die Codegröße). Müll. Es bietet dem Compiler einen einfachen Mechanismus, um weitere OPTIMIERUNGEN anzuwenden.
Martin York

37
Dies ist eine dieser Antworten, die sich als Kommentare ausgeben. Wenn Ihnen eine der veröffentlichten Antworten nicht gefällt, veröffentlichen Sie Ihre eigene Antwort und sehen Sie, wie es geht.
Dave Van den Eynde

10
Die Grundlage dieser Frage ist fehlerhaft. C ++ - Inline-Funktionen haben wenig mit dem Inlining von Compilern während der Kompilierung zu tun. Es ist bedauerlich, dass inlinees sich um ein C ++ - Schlüsselwort handelt und dass Inlining eine Compileroptimierungstechnik ist. Die richtige Antwort finden Sie in dieser Frage " Wann soll ich das Schlüsselwort inlinefür eine Funktion / Methode schreiben? ".
Deft_code

3
@ JoseVega Ihr Link wurde verstümmelt - der aktuelle Link ist exforsys.com/tutorials/c-plus-plus/inline-functions.html

Antworten:


143

Inline-Funktionen sind schneller, da Sie keine Dinge wie Parameter und die Rücksprungadresse auf den Stapel schieben und von diesem entfernen müssen. Dadurch wird Ihre Binärdatei jedoch etwas größer.

Macht es einen signifikanten Unterschied? Auf moderner Hardware für die meisten nicht merklich genug. Aber es kann einen Unterschied machen, was für manche Menschen ausreicht.

Wenn Sie etwas inline markieren, können Sie nicht garantieren, dass es inline ist. Es ist nur ein Vorschlag an den Compiler. Manchmal ist dies nicht möglich, z. B. wenn Sie eine virtuelle Funktion haben oder wenn es sich um eine Rekursion handelt. Und manchmal entscheidet sich der Compiler einfach dafür, es nicht zu verwenden.

Ich konnte sehen, dass eine solche Situation einen erkennbaren Unterschied machte:

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);

26
Wie ich vermutet habe, macht Inlining keinen Unterschied zu dem oben Gesagten. Kompiliert mit gcc 4.01. Version 1 muss Inlining verwenden: 48.318u 1.042s 5: 51.39 99.4% 0 + 0k 0 + 0io 0pf + 0w Version 2 erzwingt kein Inlining 348.311u 1.019s 5: 52.31 99.1% 0 + 0k 0 + 0io 0pf + 0w Dies ist Ein gutes Beispiel, wo allgemein bekannt ist, ist falsch.
Martin York

36
Während der Anruf selbst in der Tat wichtig ist, ist dies nur der geringfügige Gewinn, den Sie durch die Verwendung von Inline erzielen. Der Hauptgewinn besteht darin, dass der Compiler jetzt sieht, wo sich Zeiger nicht gegenseitig aliasen, wo Variablen des Aufrufers im Angerufenen landen und so weiter. Daher ist die folgende Optimierung wichtiger.
Johannes Schaub - litb

31
Es macht wahrscheinlich keinen Unterschied in diesem Snippet, da das Ergebnis der Funktion niemals verwendet wird und die Funktion keine Nebenwirkungen hat. Wir sehen einen messbaren Leistungsgewinn beim Inlining in der Bildverarbeitung.
Sockel

4
Der Grund für keinen Unterschied könnte sein, dass der Compiler von selbst inline sein könnte; oder dass der Code klein ist, sodass keine Probleme mit dem Code-Prefetch auftreten.
Einpoklum

3
@einpoklum Der Compiler hat möglicherweise sogar die gesamte Schleife optimiert.
noɥʇʎԀʎzɐɹƆ

197

Vorteile

  • Indem Sie Ihren Code dort einfügen, wo er benötigt wird, verbringt Ihr Programm weniger Zeit mit dem Funktionsaufruf und der Rückgabe von Teilen. Es soll Ihren Code schneller machen, auch wenn er größer wird (siehe unten). Das Inlining trivialer Accessoren könnte ein Beispiel für effektives Inlining sein.
  • Indem Sie es als Inline markieren, können Sie eine Funktionsdefinition in eine Header-Datei einfügen (dh sie kann in mehrere Kompilierungseinheiten aufgenommen werden, ohne dass sich der Linker beschwert).

Nachteile

  • Dies kann Ihren Code vergrößern (dh wenn Sie Inline für nicht triviale Funktionen verwenden). Als solches könnte es Paging provozieren und Optimierungen vom Compiler zunichte machen.
  • Es bricht leicht Ihre Kapselung, weil es das Innere Ihrer Objektverarbeitung freigibt (aber dann würde es auch jedes "private" Mitglied tun). Dies bedeutet, dass Sie Inlining nicht in einem PImpl-Muster verwenden dürfen.
  • Es bricht leicht Ihre Kapselung 2: C ++ Inlining wird zur Kompilierungszeit aufgelöst. Wenn Sie also den Code der Inline-Funktion ändern, müssen Sie den gesamten Code neu kompilieren, um sicherzustellen, dass er aktualisiert wird (aus dem gleichen Grund vermeide ich Standardwerte für Funktionsparameter).
  • Wenn es in einem Header verwendet wird, vergrößert es Ihre Header-Datei und verwässert so interessante Informationen (wie die Liste einer Klassenmethode) mit Code, den der Benutzer nicht interessiert (dies ist der Grund, warum ich inline-Funktionen in a deklariere Klasse, definiert sie jedoch in einem Header nach dem Klassenkörper und niemals innerhalb des Klassenkörpers.

Inlining Magic

  • Der Compiler kann die Funktionen, die Sie als Inline markiert haben, einbinden oder nicht. Es kann sich auch dafür entscheiden, Inline-Funktionen zu verwenden, die beim Kompilieren oder Verknüpfen nicht als Inline markiert sind.
  • Inline funktioniert wie ein vom Compiler gesteuertes Kopieren / Einfügen, das sich deutlich von einem Vorprozessor-Makro unterscheidet: Das Makro wird zwangsweise eingefügt, verschmutzt alle Namespaces und den Code, ist nicht einfach zu debuggen und wird sogar ausgeführt wenn der Compiler es als ineffizient eingestuft hätte.
  • Jede Methode einer Klasse, die im Hauptteil der Klasse selbst definiert ist, wird als "inline" betrachtet (auch wenn der Compiler dennoch entscheiden kann, sie nicht zu inlineieren
  • Virtuelle Methoden sollen nicht inlinierbar sein. Manchmal, wenn der Compiler den Typ des Objekts sicher kennen kann (dh das Objekt wurde innerhalb desselben Funktionskörpers deklariert und erstellt), wird sogar eine virtuelle Funktion eingefügt, da der Compiler den Typ des Objekts genau kennt.
  • Vorlagenmethoden / -funktionen sind nicht immer inline (durch das Vorhandensein in einem Header werden sie nicht automatisch inline geschaltet).
  • Der nächste Schritt nach "Inline" ist das Template-Metaprograming. Dh durch "Inlinen" Ihres Codes zur Kompilierungszeit kann der Compiler manchmal das Endergebnis einer Funktion ableiten ... So kann ein komplexer Algorithmus manchmal auf eine Art return 42 ;Anweisung reduziert werden . Das ist für mich extremes Inlining . Es kommt im wirklichen Leben selten vor, es verlängert die Kompilierungszeit, bläht Ihren Code nicht auf und beschleunigt Ihren Code. Aber wie der Gral, versuchen Sie nicht, ihn überall anzuwenden, da die meisten Verarbeitungen nicht auf diese Weise aufgelöst werden können ... Trotzdem ist das sowieso cool ...
    :-p

Sie sagten, es bricht leicht Ihre Kapselung. Würden Sie es bitte anhand eines Beispiels erklären?
Zerstörer

6
@PravasiMeet: Es ist C ++. Angenommen, Sie liefern eine DLL / gemeinsam genutzte Bibliothek an einen Client, der dagegen kompiliert. Die Inline-Funktion foo, die die Mitgliedsvariable X verwendet und die Arbeit Y ausführt, wird in den Code des Clients eingefügt. Angenommen, Sie müssen eine aktualisierte Version Ihrer DLL bereitstellen, in der Sie die Mitgliedsvariable in Z geändert haben, und zusätzlich zu Arbeit Y eine Arbeit YY hinzufügen. Der Client kopiert nur die DLL in sein Projekt und BOOM, weil der Code von foo in ihrer Binärdatei ist nicht der aktualisierte Code, den Sie geschrieben haben ... Obwohl der Client keinen legalen Zugriff auf Ihren privaten Code hat, macht Inlining ihn ziemlich "öffentlich".
Paercebal

@paercebal Können Sie in Bezug auf Ihren vorletzten Aufzählungspunkt ein Beispiel geben, wenn eine Funktionsvorlage nicht inline ist? Ich dachte, sie wären immer inline, obwohl ich jetzt keine Referenz zur Hand habe (ein einfacher Test scheint dies jedoch zu bestätigen).
Konrad Rudolph

@KonradRudolph In n4594 sehe ich : 3.2/6: There can be more than one definition of [..] inline function with external linkage [..] non-static function template. Bei 5.1.5 / 6 For a generic lambda, the closure type has a public inline function call operator member template. Und 7.1.2/2: the use of inline keyword is to declare an inline functionwo es ein Vorschlag ist, den Funktionskörper am Point of Call einzubinden. Daher
komme

Kapselung ist kaputt? Wie? Die Kapselung ist für die Programmierer vorgesehen, nicht für die tatsächlichen Objekte im Speicher. an diesem Punkt kümmert sich niemand. Selbst wenn Sie eine Bibliothek verteilen, kann der Compiler entscheiden, ob er inline arbeiten oder nicht. Wenn Sie also am Ende eine neue Bibliothek erhalten, müssen Sie nur alles neu kompilieren, was die Funktionen und Objekte aus dieser Bibliothek verwendet.
FalcoGer

42

In archaischem C und C ++ inlineist wie folgt register: ein Vorschlag (nichts weiter als ein Vorschlag) an den Compiler über eine mögliche Optimierung.

inlineWeist den Linker in modernem C ++ an, dass mehrere Definitionen (keine Deklarationen) in verschiedenen Übersetzungseinheiten gleich sind und der Linker eine frei behalten und alle anderen verwerfen kann.

inline ist obligatorisch, wenn eine Funktion (egal wie komplex oder "linear") in einer Header-Datei definiert ist, damit mehrere Quellen sie einschließen können, ohne dass der Linker einen Fehler "Mehrfachdefinition" erhält.

Innerhalb einer Klasse definierte Elementfunktionen sind standardmäßig "inline", ebenso wie Vorlagenfunktionen (im Gegensatz zu globalen Funktionen).

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

Beachten Sie die Aufnahme von fileA.h in zwei CPP-Dateien, was zu zwei Instanzen von führt afunc(). Der Linker verwirft einen von ihnen. Wenn nein inlineangegeben ist, beschwert sich der Linker.


16

Inlining ist ein Vorschlag an den Compiler, den er ignorieren kann. Es ist ideal für kleine Codebits.

Wenn Ihre Funktion inline ist, wird sie im Grunde genommen in den Code eingefügt, in dem der Funktionsaufruf ausgeführt wird, anstatt tatsächlich eine separate Funktion aufzurufen. Dies kann die Geschwindigkeit verbessern, da Sie den eigentlichen Anruf nicht tätigen müssen.

Es unterstützt auch CPUs beim Pipelining, da sie die Pipeline nicht mit neuen Anweisungen neu laden müssen, die durch einen Aufruf verursacht werden.

Der einzige Nachteil ist eine mögliche Vergrößerung der Binärdatei, aber solange die Funktionen klein sind, spielt dies keine große Rolle.

Ich überlasse diese Art von Entscheidungen heutzutage eher den Compilern (na ja, die klugen sowieso). Die Leute, die sie geschrieben haben, neigen dazu, die zugrunde liegenden Architekturen weitaus detaillierter zu kennen.


12

Die Inline-Funktion ist die von den Compilern verwendete Optimierungstechnik. Man kann dem Funktionsprototyp einfach ein Inline-Schlüsselwort voranstellen, um eine Funktion inline zu machen. Die Inline-Funktion weist den Compiler an, den gesamten Funktionskörper einzufügen, wo immer diese Funktion im Code verwendet wurde.

Vorteile: -

  1. Es erfordert keinen Funktionsaufruf-Overhead.

  2. Es spart auch Overhead von Variablen Push / Pop auf dem Stapel während des Funktionsaufrufs.

  3. Es spart auch Overhead des Rückrufs von einer Funktion.

  4. Es erhöht die Referenzlokalität durch Verwendung des Befehls-Cache.

  5. Nach dem In-Lining kann der Compiler bei Bedarf auch eine prozedurale Optimierung anwenden. Dies ist die wichtigste, auf diese Weise kann sich der Compiler jetzt auf die Eliminierung von totem Code konzentrieren, die Verzweigungsvorhersage, die Eliminierung von Induktionsvariablen usw. stärker belasten.

Um mehr darüber zu erfahren, folgen Sie diesem Link http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html


4
1) Es ist ein Vorschlag, keine Anweisung. 2) Es kann aufgrund der Zunahme der Codegröße zu mehr Cache-Fehlern führen, wenn eine häufig verwendete Funktion häufig eingebunden ist
Flexo

3
Ist der Link am Ende Ihr persönlicher Blog? Wenn dies der Fall ist, sollten Sie es als solches deklarieren, da es sonst wie Spam aussieht.
Flexo

6

Ich möchte hinzufügen, dass Inline-Funktionen beim Erstellen einer gemeinsam genutzten Bibliothek von entscheidender Bedeutung sind. Ohne Inline-Markierungsfunktion wird es in binärer Form in die Bibliothek exportiert. Es wird auch in der Symboltabelle angezeigt, wenn es exportiert wird. Auf der anderen Seite werden Inline-Funktionen weder in die Bibliotheksbinärdateien noch in die Symboltabelle exportiert.

Dies kann kritisch sein, wenn die Bibliothek zur Laufzeit geladen werden soll. Es kann auch binär kompatible Bibliotheken treffen. Verwenden Sie in solchen Fällen nicht Inline.


@ Johnsyweb: Lies meine Antwort sorgfältig. Was Sie gesagt haben, ist wahr, wenn Sie eine ausführbare Datei erstellen. Aber der Compiler kann inlinebeim Erstellen einer gemeinsam genutzten Bibliothek nicht einfach ignorieren !
Doc

4

Während der Optimierung werden viele Compiler Funktionen inline, auch wenn Sie sie nicht markiert haben. Sie müssen Funktionen im Allgemeinen nur dann als Inline markieren, wenn Sie etwas wissen, was der Compiler nicht weiß, da er normalerweise selbst die richtige Entscheidung treffen kann.


Viele Compiler werden dies auch nicht tun, MSVC zum Beispiel wird dies nicht tun, es sei denn, Sie sagen es
Paulm

4

inlineMit dieser Option können Sie eine Funktionsdefinition in eine Header-Datei und #includediese Header-Datei in mehrere Quelldateien einfügen, ohne die eine Definitionsregel zu verletzen.


3

Im Allgemeinen ist es heutzutage eine Zeitverschwendung, wenn sich ein moderner Compiler Gedanken über das Inlining macht. Der Compiler sollte all diese Überlegungen für Sie optimieren, indem er den Code selbst analysiert und die an den Compiler übergebenen Optimierungsflags angibt. Wenn Sie Wert auf Geschwindigkeit legen, weisen Sie den Compiler an, die Geschwindigkeit zu optimieren. Wenn Sie sich für Speicherplatz interessieren, weisen Sie den Compiler an, den Speicherplatz zu optimieren. Wie eine andere Antwort angedeutet hat, wird ein anständiger Compiler sogar automatisch inline, wenn es wirklich Sinn macht.

Wie bereits erwähnt, garantiert die Verwendung von Inline keine Inline-Funktion. Wenn Sie dies garantieren möchten, müssen Sie ein Makro anstelle einer Inline-Funktion definieren, um dies zu tun.

Wann muss ein Makro inline und / oder definiert werden, um die Aufnahme zu erzwingen? - Nur wenn Sie eine nachgewiesene und notwendige nachgewiesene Geschwindigkeitssteigerung für einen kritischen Codeabschnitt haben, von dem bekannt ist, dass er sich auf die Gesamtleistung der Anwendung auswirkt.


… Wenn Sie sich für Speicherplatz interessieren, weisen Sie den Compiler an, den Speicherplatz zu optimieren. Wenn Sie den Compiler anweisen, die Geschwindigkeit zu optimieren, kann dies zu kleineren Binärdateien mit C ++ und C führen. Wenn Sie den Compiler anweisen, den Speicherplatz zu optimieren, kann dies zu einer schnelleren Ausführung führen. Diese Funktionen funktionieren jedoch nicht immer wie angegeben. Menschen haben die Fähigkeit, einige Aspekte ihres Programms besser zu verstehen als die allgemeinen Interpretationen eines Compilers (die auch brauchbar schnell bleiben müssen). menschliches Eingreifen muss keine schlechte Sache sein.
Justin

3

Es geht nicht nur um Leistung. Sowohl C ++ als auch C werden für die eingebettete Programmierung verwendet und befinden sich auf der Hardware. Wenn Sie beispielsweise einen Interrupt-Handler schreiben möchten, müssen Sie sicherstellen, dass der Code sofort ausgeführt werden kann, ohne dass zusätzliche Register und / oder Speicherseiten ausgetauscht werden. Dann ist Inline praktisch. Gute Compiler machen selbst ein "Inlining", wenn Geschwindigkeit benötigt wird, aber "Inline" zwingt sie.


1

Fiel in die gleichen Schwierigkeiten mit Inlining-Funktionen in so Bibliotheken. Es scheint, dass Inline-Funktionen nicht in die Bibliothek kompiliert werden. Infolgedessen gibt der Linker einen Fehler "undefinierte Referenz" aus, wenn eine ausführbare Datei die Inline-Funktion der Bibliothek verwenden möchte. (ist mir beim Kompilieren der Qt-Quelle mit gcc 4.5 passiert.


1

Warum nicht standardmäßig alle Funktionen inline schalten? Weil es ein technischer Kompromiss ist. Es gibt mindestens zwei Arten der "Optimierung": Beschleunigung des Programms und Reduzierung der Größe (Speicherbedarf) des Programms. Inlining beschleunigt im Allgemeinen die Dinge. Der Overhead des Funktionsaufrufs entfällt, wodurch vermieden wird, dass Parameter vom Stapel gedrückt und dann abgerufen werden. Dies vergrößert jedoch auch den Speicherbedarf des Programms, da jetzt jeder Funktionsaufruf durch den vollständigen Code der Funktion ersetzt werden muss. Um die Sache noch komplizierter zu machen, denken Sie daran, dass die CPU häufig verwendete Speicherblöcke in einem Cache auf der CPU für einen ultraschnellen Zugriff speichert. Wenn Sie das Speicher-Image des Programms groß genug machen, kann Ihr Programm den Cache nicht effizient nutzen, und im schlimmsten Fall kann Inlining Ihr Programm tatsächlich verlangsamen.


1

Unser Informatikprofessor forderte uns auf, Inline niemals in einem C ++ - Programm zu verwenden. Auf die Frage nach dem Grund erklärte er uns freundlich, dass moderne Compiler erkennen sollten, wann Inline automatisch verwendet werden soll.

Ja, die Inline kann eine Optimierungstechnik sein, die nach Möglichkeit verwendet werden kann, aber anscheinend ist dies bereits für Sie erledigt, wenn es möglich ist, eine Funktion trotzdem zu inline.


5
Ihr Professor ist leider völlig falsch. inlinein C ++ hat zwei sehr unterschiedliche Bedeutungen - nur eine davon bezieht sich auf die Optimierung, und Ihr Professor hat diesbezüglich Recht. Die zweite Bedeutung von inlineist jedoch häufig erforderlich, um die Ein-Definition-Regel zu erfüllen .
Konrad Rudolph

-1

Schlussfolgerung aus einer anderen Diskussion hier:

Gibt es Nachteile bei Inline-Funktionen?

Anscheinend ist an der Verwendung von Inline-Funktionen nichts auszusetzen.

Beachten Sie jedoch die folgenden Punkte!

  • Übermäßiger Gebrauch von Inlining kann Programme tatsächlich langsamer machen. Abhängig von der Größe einer Funktion kann durch Inlining die Codegröße erhöht oder verringert werden. Das Inlining einer sehr kleinen Accessor-Funktion verringert normalerweise die Codegröße, während das Inlining einer sehr großen Funktion die Codegröße dramatisch erhöhen kann. Auf modernen Prozessoren wird kleinerer Code aufgrund der besseren Verwendung des Anweisungscaches normalerweise schneller ausgeführt. - Google-Richtlinien

  • Die Geschwindigkeitsvorteile von Inline-Funktionen nehmen mit zunehmender Größe der Funktion tendenziell ab. Irgendwann wird der Overhead des Funktionsaufrufs im Vergleich zur Ausführung des Funktionskörpers gering, und der Nutzen geht verloren - Quelle

  • Es gibt wenige Situationen, in denen eine Inline-Funktion möglicherweise nicht funktioniert:

    • Für eine Funktion, die Werte zurückgibt; wenn eine return-Anweisung vorhanden ist.
    • Für eine Funktion, die keine Werte zurückgibt; Wenn eine Schleife, ein Schalter oder eine goto-Anweisung vorhanden ist.
    • Wenn eine Funktion rekursiv ist. -Quelle
  • Das __inlineSchlüsselwort bewirkt, dass eine Funktion nur dann eingefügt wird, wenn Sie die Optimierungsoption angeben. Wenn die Optimierung angegeben __inlineist, hängt es von der Einstellung der Inline-Optimierungsoption ab , ob die Option berücksichtigt wird oder nicht . Standardmäßig ist die Inline-Option immer dann wirksam, wenn das Optimierungsprogramm ausgeführt wird. Wenn Sie Optimieren angeben, müssen Sie auch die Option noinline angeben, wenn das __inlineSchlüsselwort ignoriert werden soll. -Quelle


3
Wäre wahr, wenn die Inline ein Befehl und kein Hinweis für den Compiler wäre. Der Compiler entscheidet tatsächlich, was inline sein soll.
Martin York

1
@LokiAstari Ich weiß, dass Inline eine Anfrage an den Compiler ist. Mein Argument ist: Wenn es ein Hinweis auf den Compiler ist, sollten wir es dem Compiler überlassen, zu entscheiden, was am besten ist. Warum Sie Inline auf irgendeine Weise verwenden sollten, auch wenn Sie Inline verwenden, ist es immer noch der Compiler, der die endgültige Entscheidung trifft. Ich frage mich auch, ob Microsoft _forceinline eingeführt hat.
Krishna Oza

@krish_oza: Mein Kommentar hier. Geht es um diese Antwort. Die Antwort hier ist völlig falsch. Da der Compiler das inlineSchlüsselwort ignoriert, um zu bestimmen, ob Inline- Code verwendet werden soll, sind alle oben genannten Punkte falsch. Sie wären wahr, wenn der Compiler das Schlüsselwort zum Inlining verwenden würde (es wird nur zum Bestimmen der Markierung mehrerer Definitionen für Verknüpfungszwecke verwendet).
Martin York
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.