Wann sollte ich das Schlüsselwort inline
für eine Funktion/Methode in C++ schreiben?
Nachdem Sie einige Antworten, einige verwandte Fragen gesehen haben:
Wann sollte ich nicht das Schlüsselwort 'inline' für eine Funktion/Methode in C++ schreiben?
Wann wird der Compiler nicht wissen, wann er eine Funktion/Methode 'inline' machen soll?
Ist es wichtig, wenn eine Anwendung Multithreading ist, wenn man für eine Funktion/Methode 'Inline' schreibt?
Oh man, einer meiner Lieblingstaler.
inline
ist mehr wie static
oder extern
als eine Anweisung, die den Compiler auffordert, Ihre Funktionen zu integrieren. extern
, static
, inline
sind Verknüpfungsanweisungen, die fast ausschließlich vom Linker und nicht vom Compiler verwendet werden.
Es wird gesagt, dass inline
dem Compiler andeutet, dass die Funktion Ihrer Meinung nach inline sein sollte. Das mag 1998 der Fall gewesen sein, aber ein Jahrzehnt später benötigt der Compiler keine derartigen Hinweise. Ganz zu schweigen davon, dass Menschen in der Regel falsch liegen, wenn es um die Optimierung von Code geht. Daher ignorieren die meisten Compiler den "Hinweis".
static
- Der Name der Variablen/Funktion kann nicht in anderen Übersetzungseinheiten verwendet werden. Der Linker muss sicherstellen, dass er nicht versehentlich eine statisch definierte Variable/Funktion einer anderen Übersetzungseinheit verwendet.
extern
- Verwenden Sie diesen Variablen-/Funktionsnamen in dieser Übersetzungseinheit, aber beschweren Sie sich nicht, wenn er nicht definiert ist. Der Linker wird es aussortieren und sicherstellen, dass der gesamte Code, der versucht hat, ein externes Symbol zu verwenden, seine Adresse hat.
inline
- Diese Funktion wird in mehreren Übersetzungseinheiten definiert, keine Sorge. Der Linker muss sicherstellen, dass alle Übersetzungseinheiten eine einzige Instanz der Variablen/Funktion verwenden.
Hinweis: Die Deklaration von Vorlagen inline
ist im Allgemeinen sinnlos, da sie bereits die Verknüpfungssemantik von inline
haben. Die explizite Spezialisierung und Instanziierung von Vorlagen erfordert die Verwendung von inline
.
Spezifische Antworten auf Ihre Fragen:
Wann sollte ich das Schlüsselwort 'inline' für eine Funktion/Methode in C++ schreiben?
Nur wenn die Funktion in einer Kopfzeile definiert werden soll. Genauer gesagt nur, wenn die Definition der Funktion in mehreren Übersetzungseinheiten angezeigt werden kann. Es ist eine gute Idee, kleine (wie in einer Zeile) Funktionen in der Header-Datei zu definieren, da der Compiler dadurch mehr Informationen erhält, mit denen er arbeiten kann, während er den Code optimiert. Dies verlängert auch die Kompilierungszeit.
Wann sollte ich das Schlüsselwort 'inline' für eine Funktion/Methode in C++ nicht schreiben?
Fügen Sie Inline nicht hinzu, nur weil Sie glauben, dass Ihr Code schneller ausgeführt wird, wenn der Compiler ihn einfügt.
Wann wird der Compiler nicht wissen, wann er eine Funktion/Methode 'inline' machen soll?
Im Allgemeinen kann der Compiler dies besser als Sie. Der Compiler kann jedoch keinen Code einbinden, wenn er nicht über die Funktionsdefinition verfügt. Im maximal optimierten Code werden normalerweise alle private
Methoden eingeblendet, ob Sie danach fragen oder nicht.
Verwenden Sie __attribute__(( noinline ))
und in Visual Studio __declspec(noinline)
, um Inlining in GCC zu verhindern.
Ist es wichtig, wenn eine Anwendung mehrere Threads ausführt, wenn eine Funktion/Methode inline geschrieben wird?
Multithreading beeinflusst das Inlining in keiner Weise.
Ich möchte zu allen großartigen Antworten in diesem Thread mit einem überzeugenden Beispiel beitragen, um verbleibende Missverständnisse zu zerstreuen.
Gegeben zwei Quelldateien, wie zum Beispiel:
inline111.cpp:
#include <iostream>
void bar();
inline int fun() {
return 111;
}
int main() {
std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
bar();
}
inline222.cpp:
#include <iostream>
inline int fun() {
return 222;
}
void bar() {
std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
}
Fall A:
Kompilieren:
g++ -std=c++11 inline111.cpp inline222.cpp
Ausgabe:
inline111: fun() = 111, &fun = 0x4029a0
inline222: fun() = 111, &fun = 0x4029a0
Diskussion:
Auch wenn Sie identische Definitionen Ihrer Inline-Funktionen haben sollten, markiert der C++ - Compiler diese nicht, wenn dies nicht der Fall ist (tatsächlich gibt es aufgrund von separate Kompilierung keine Möglichkeiten, dies zu überprüfen). Dies zu gewährleisten, liegt in Ihrer eigenen Verantwortung!
Der Linker beschwert sich nicht über One Definition Rule, da fun()
als inline
deklariert ist. Da jedoch inline111.cpp die erste vom Compiler verarbeitete Übersetzungseinheit ist (die tatsächlich fun()
aufruft), instanziiert der Compiler fun()
bei - first Anrufbegegnung in inline111.cpp . Wenn der Compiler beschließt nicht , fun()
bei seinem Aufruf von einer anderen Stelle in Ihrem Programm aus zu erweitern (zB von Inline222.cpp ) wird der Aufruf von fun()
immer mit seiner Instanz verknüpft, die aus inline111.cpp (dem Aufruf von fun()
inside inline222.cpp erzeugt möglicherweise auch eine Instanz in dieser Übersetzungseinheit, bleibt jedoch nicht verbunden). Dies ist in der Tat aus den identischen &fun = 0x4029a0
Ausdrucken ersichtlich.
Schließlich, trotz des inline
Vorschlags an den Compiler, tatsächlich zu erweitern den Einzeiler fun()
, ignoriert Ihren Vorschlag vollständig, was ist klar, weil fun() = 111
in beiden Zeilen.
Fall B:
Kompilieren(umgekehrte Reihenfolge beachten):
g++ -std=c++11 inline222.cpp inline111.cpp
Ausgabe:
inline111: fun() = 222, &fun = 0x402980
inline222: fun() = 222, &fun = 0x402980
Diskussion:
In diesem Fall wird behauptet, was in Fall A besprochen wurde.
Beachten Sie einen wichtigen Punkt, wenn Sie den tatsächlichen Aufruf von fun()
in inline222.cpp auskommentieren (zB auskommentieren cout
- Anweisung in inline222.cpp vollständig, dann wird fun()
trotz der Kompilierungsreihenfolge Ihrer Übersetzungseinheiten beim ersten Aufrufen in inline111.cpp , was zu einem Ausdruck für Case B als inline111: fun() = 111, &fun = 0x402980
.
Fall C:
Compile(notice -O2):
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
oder
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
Ausgabe:
inline111: fun() = 111, &fun = 0x402900
inline222: fun() = 222, &fun = 0x402900
Diskussion:
-O2
-Optimierung den Compiler auf, tatsächlich zu erweitern die Funktionen, die eingebunden werden können (Beachten Sie auch, dass -fno-inline
Standard ohne Optimierungsoptionen). Wie aus dem Ausdruck hier hervorgeht, wurde das fun()
tatsächlich inline expandiert (gemäß seiner Definition in dieser bestimmten Übersetzungseinheit), was zu zwei - different fun()
Ausdrucke. Trotzdem gibt es immer noch nur eine global verknüpfte Instanz von fun()
(wie vom Standard gefordert), wie aus identisch&fun
hervorgeht. ausdrucken.Sie müssen Ihre Funktion noch explizit einbinden, wenn Sie eine Vorlagenspezialisierung durchführen (wenn sich die Spezialisierung in einer .h-Datei befindet)
1) Heutzutage so ziemlich nie. Wenn es eine gute Idee ist, eine Funktion zu integrieren, wird der Compiler dies ohne Ihre Hilfe tun.
2) immer. Siehe # 1.
(Bearbeitet, um zu reflektieren, dass Sie Ihre Frage in zwei Fragen zerlegt haben ...)
Wann sollte ich das Schlüsselwort 'inline' für eine Funktion/Methode in C++ nicht schreiben?
Wenn die Funktion in der .cpp
Datei, sollten Sie nicht das Schlüsselwort schreiben.
Wann weiß der Compiler nicht, wann er eine Funktion/Methode 'inline' machen soll?
Es gibt keine solche Situation. Der Compiler kann keine Funktion inline machen. Alles, was es tun kann, ist, einige oder alle Aufrufe der Funktion inline zu schalten. Dies ist nicht möglich, wenn der Code der Funktion fehlt (in diesem Fall muss der Linker dies tun, wenn er dazu in der Lage ist).
Ist es wichtig, wenn eine Anwendung mehrere Threads ausführt, wenn eine Funktion/Methode inline geschrieben wird?
Nein, das spielt überhaupt keine Rolle.
Dies hängt vom verwendeten Compiler ab. Vertrauen Sie nicht blindlings darauf, dass Compiler heutzutage besser als Menschen wissen, wie man inline arbeitet, und verwenden Sie es niemals aus Leistungsgründen, da es sich eher um eine Verknüpfungsrichtlinie als um einen Optimierungshinweis handelt. Obwohl ich der Meinung bin, dass diese Argumente ideologisch korrekt sind, könnte die Begegnung mit der Realität eine andere Sache sein.
Nachdem ich mehrere Threads gelesen hatte, versuchte ich aus Neugier die Auswirkungen von Inline auf den Code, an dem ich gerade arbeite, und die Ergebnisse waren, dass ich messbare Beschleunigung für GCC und keine Beschleunigung für Intel Compiler bekam.
(Weitere Details: Mathematische Simulationen mit wenigen außerhalb der Klasse definierten kritischen Funktionen, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3); Hinzufügen von Inline zu kritischen Punkten verursacht + 6% Geschwindigkeitssteigerung mit GCC-Code).
Wenn Sie also GCC 4.6 als modernen Compiler qualifizieren, ist die Inline-Direktive nach wie vor von Bedeutung, wenn Sie CPU-intensive Aufgaben schreiben und genau wissen, wo der Engpass liegt.
In Wirklichkeit so ziemlich nie. Sie schlagen lediglich vor, dass der Compiler eine bestimmte Funktion inline ausführt (z. B. alle Aufrufe dieser Funktion mit ihrem Hauptteil ersetzen). Natürlich gibt es keine Garantie: Der Compiler kann die Direktive ignorieren.
Der Compiler kann solche Dinge im Allgemeinen gut erkennen und optimieren.
standardmäßig integriert gcc beim Kompilieren ohne aktivierte Optimierung keine Funktionen. Ich kenne mich mit Visual Studio nicht aus - deft_code
Ich habe dies für Visual Studio 9 (15.00.30729.01) durch Kompilieren mit/FAcs und Betrachten des Assembly-Codes überprüft: Der Compiler hat Aufrufe an Member-Funktionen ohne aktivierte Optimierung im Modus Debug erzeugt. Auch wenn die Funktion mit __ forceinline markiert ist, wird kein Inline-Laufzeitcode erzeugt.
Die C++ - Inline-Funktion ist ein leistungsfähiges Konzept, das häufig für Klassen verwendet wird. Wenn eine Funktion inline ist, platziert der Compiler an jedem Punkt, an dem die Funktion zur Kompilierungszeit aufgerufen wird, eine Kopie des Codes dieser Funktion.
Jede Änderung an einer Inline-Funktion kann dazu führen, dass alle Clients der Funktion neu kompiliert werden müssen, da der Compiler den gesamten Code erneut ersetzen muss, andernfalls wird die alte Funktionalität beibehalten.
Um eine Funktion einzurichten, setzen Sie das Schlüsselwort inline vor den Funktionsnamen und definieren Sie die Funktion, bevor Sie die Funktion aufrufen. Der Compiler kann das Inline-Qualifikationsmerkmal ignorieren, wenn die definierte Funktion mehr als eine Zeile ist.
Eine Funktionsdefinition in einer Klassendefinition ist eine Inline-Funktionsdefinition, auch ohne die Verwendung des Inline-Bezeichners.
Das folgende Beispiel verwendet die Inline-Funktion, um maximal zwei Zahlen zurückzugeben
#include <iostream>
using namespace std;
inline int Max(int x, int y) { return (x > y)? x : y; }
// Main function for the program
int main() {
cout << "Max (100,1010): " << Max(100,1010) << endl;
return 0;
}
weitere Informationen finden Sie unter hier .
Sie möchten es ganz an den Anfang stellen, bevor Sie den Rückgabetyp eingeben. Aber die meisten Compiler ignorieren es. Wenn es definiert ist und einen kleineren Codeblock enthält, wird es von den meisten Compilern ohnehin als inline betrachtet.