wake-up-neo.com

Warum sind C++ - Inline-Funktionen im Header?

NB Hierbei geht es nicht darum, wie Inline-Funktionen verwendet werden oder wie sie funktionieren, sondern warum sie so gemacht werden, wie sie sind.

Die Deklaration einer Klassenmitgliedsfunktion muss keine Funktion als inline definieren, es handelt sich lediglich um die tatsächliche Implementierung der Funktion. Zum Beispiel in der Header-Datei:

struct foo{
    void bar(); // no need to define this as inline
}

Warum muss also die Inline-Implementierung einer Klassenfunktion in der Header-Datei sein? Warum kann ich der Inline-Funktion nicht die .cpp-Datei zuweisen? Wenn ich versuche, die Inline-Definition in die .cpp-Datei zu schreiben, würde ich folgende Fehlermeldung erhalten:

error LNK2019: unresolved external symbol 
"public: void __thiscall foo::bar(void)"
([email protected]@@QAEXXZ) referenced in function _main 
1>C:\Users\Me\Documents\Visual Studio 2012\Projects\inline\Debug\inline.exe 
: fatal error LNK1120: 1 unresolved externals
96
thecoshman

Die Definition einer inline-Funktion muss nicht in einer Header-Datei enthalten sein. Aufgrund der one-Definitionsregel für Inline-Funktionen muss in jeder Übersetzungseinheit, die sie verwendet, eine identische Definition für die Funktion vorhanden sein.

Dies erreichen Sie am einfachsten, indem Sie die Definition in eine Header-Datei einfügen.

Wenn Sie die Definition einer Funktion in einer einzigen Quelldatei speichern möchten, sollten Sie sie nicht als inline deklarieren. Eine Funktion, die nicht inline deklariert ist, bedeutet nicht, dass der Compiler die Funktion nicht inline aufnehmen kann.

Ob Sie eine Funktion inline deklarieren sollten oder nicht, ist in der Regel eine Entscheidung, die Sie auf Grundlage der Version der one-Definitionsregeln treffen sollten, für die es am sinnvollsten ist, wenn Sie diese befolgen. Das Hinzufügen von inline und das anschließende Eingrenzen durch die nachfolgenden Einschränkungen machen wenig Sinn.

98
CB Bailey

Es gibt zwei Möglichkeiten, es zu betrachten:

  1. Inline-Funktionen werden im Header deklariert, da der Compiler zum Inline-Aufruf eines Funktionsaufrufs den Funktionskörper sehen kann. Damit ein naiver Compiler dies tun kann, muss sich der Funktionskörper in derselben Übersetzungseinheit befinden wie der Aufruf. (Ein moderner Compiler kann über Übersetzungseinheiten hinweg optimieren. Daher kann ein Funktionsaufruf auch eingeblendet werden, obwohl sich die Funktionsdefinition in einer separaten Übersetzungseinheit befindet. Diese Optimierungen sind jedoch teuer, nicht immer aktiviert und werden nicht immer von der unterstützt Compiler)

  2. funktionen, die im Header deklariert sind, müssen mit inline gekennzeichnet sein, da andernfalls jede Übersetzungseinheit, die den Header enthält, eine Definition der Funktion enthält und der Linker sich über mehrere Definitionen beschwert (eine Verletzung der One-Definitions-Regel). Das Schlüsselwort inline unterdrückt dies, so dass mehrere Übersetzungseinheiten (identische) Definitionen enthalten können.

Die beiden Erklärungen lassen sich darauf zurückführen, dass das Schlüsselwort inline nicht genau das tut, was Sie erwarten.

Ein C++ - Compiler kann das Inlining Optimierung beliebig anwenden (Ersetzen eines Funktionsaufrufs durch den Rumpf der aufgerufenen Funktion, um den Aufruf-Overhead zu sparen), solange dies das beobachtbare Verhalten nicht ändert des Programms.

Das inline-Schlüsselwort macht es dem Compiler einfacher, diese Optimierung anzuwenden, indem die Funktionsdefinition in mehreren Übersetzungseinheiten sichtbar sein kann. Die Verwendung des Schlüsselworts bedeutet jedoch nicht, dass der Compiler has Um die Funktion zu integrieren, und not mit dem Schlüsselwort verbietet der Compiler nicht, die Funktion zu inline zu setzen.

94
jalf

Dies ist eine Beschränkung des C++ - Compilers. Wenn Sie die Funktion in den Header einfügen, können alle cpp-Dateien, in denen sie eingebettet werden können, die "Quelle" Ihrer Funktion sehen und das Inlining kann vom Compiler ausgeführt werden. Andernfalls müsste der Linker das Inlining vornehmen (jede cpp-Datei wird separat in einer obj-Datei kompiliert). Das Problem ist, dass es viel schwieriger wäre, dies im Linker zu tun. Ein ähnliches Problem besteht bei "Vorlagen" -Klassen/-Funktionen. Sie müssen vom Compiler instanziiert werden, da der Linker Probleme haben würde, eine Instanz davon zu erstellen (eine spezialisierte Version davon zu erstellen). Einige neuere Compiler/Linker können eine "Zwei-Durchlauf" -Kompilierung/Verknüpfung durchführen, wobei der Compiler einen ersten Durchlauf ausführt. Dann erledigt der Linker seine Arbeit und ruft den Compiler an, um nicht aufgelöste Dinge (Inline/Templates ...) zu lösen.

20
xanatos

Der Grund ist, dass der Compiler tatsächlich diedefinitionsehen muss, um sie anstelle des Aufrufs ablegen zu können. 

Denken Sie daran, dass C und C++ ein sehr vereinfachtes Kompilierungsmodell verwenden, bei dem der Compiler immer nur eine Übersetzungseinheit sieht. (Dies schlägt beim Export fehl, was der Hauptgrund ist, warum nur ein Anbieter ihn tatsächlich implementiert hat.)

8
sbi

Das c ++ inline-Schlüsselwort ist irreführend. Dies bedeutet nicht "Inline-Funktion". Wenn eine Funktion als Inline definiert ist, bedeutet dies einfach, dass sie mehrmals definiert werden kann, solange alle Definitionen gleich sind. Es ist absolut legal, dass eine mit inline gekennzeichnete Funktion eine echte Funktion ist, die aufgerufen wird, anstatt an der Stelle, an der sie aufgerufen wird, Code zu erhalten.

Die Definition einer Funktion in einer Header-Datei ist für Vorlagen erforderlich, da z. Eine Klasse mit Vorlagen ist nicht wirklich eine Klasse, sondern eine Vorlage für eine Klasse, von der Sie mehrere Variationen machen können. Damit der Compiler z. Erstellen Sie eine Foo<int>::bar()-Funktion Wenn Sie mit der Foo-Vorlage eine Foo-Klasse erstellen , muss die tatsächliche Definition von Foo<T>::bar() sichtbar sein.

8
Erik

Ich weiß, dass dies ein alter Thread ist, aber ich dachte, ich sollte das Schlüsselwort extern erwähnen. Ich bin kürzlich auf dieses Problem gestoßen und habe es wie folgt gelöst

Helfer.h

namespace DX
{
    extern inline void ThrowIfFailed(HRESULT hr);
}

Helper.cpp

namespace DX
{
    inline void ThrowIfFailed(HRESULT hr)
    {
        if (FAILED(hr))
        {
            std::stringstream ss;
            ss << "#" << hr;
            throw std::exception(ss.str().c_str());
        }
    }
}
3
flamewave000

Weil der Compiler sie sehen muss, um inline sie. Headerdateien sind die "Komponenten", die normalerweise in anderen Übersetzungseinheiten enthalten sind.

#include "file.h"
// Ok, now me (the compiler) can see the definition of that inline function. 
// So I'm able to replace calls for the actual implementation.
1

Inline-Funktionen

In C++ ist ein Makro nur eine Inline-Funktion. SO Jetzt werden Makros vom Compiler gesteuert.

  • Wichtig : Wenn wir eine Funktion innerhalb der Klasse definieren, wird sie automatisch zu Inline

Der Code der Inline-Funktion wird an der Stelle ersetzt, an der er aufgerufen wird, um den Aufwand der aufrufenden Funktion zu reduzieren.

In einigen Fällen kann das Inlining der Funktion nicht funktionieren, z 

  • Wenn statische Variable innerhalb der Inline-Funktion verwendet wird.

  • Wenn die Funktion kompliziert ist.

  • Wenn rekursiver Aufruf der Funktion 

  • Wenn die Adresse der Funktion implizit oder explizit verwendet wird

Funktion, die außerhalb der Klasse definiert ist, kann inline werden 

inline int AddTwoVar(int x,int y); //This may not become inline 

inline int AddTwoVar(int x,int y) { return x + y; } // This becomes inline

Innerhalb der Klasse definierte Funktionen werden auch inline 

// Inline SpeedMeter functions
class SpeedMeter
{
    int speed;
    public:
    int getSpeed() const { return speed; }
    void setSpeed(int varSpeed) { speed = varSpeed; }
};
int main()
{
    SpeedMeter objSM;
    objSM.setSpeed(80);
    int speedValue = A.getSpeed();
} 

Hier werden sowohl die getSpeed- als auch die setSpeed-Funktionen inline

0
Saurabh Raoot