C++ Kurs

Inline (Member-)Funktionen

Die Themen:

Einführung

In diesem Kapitel werden wir einmal etwas für die Laufzeit-Optimierung einer Anwendung tun.

Wei bekannt, müssen für den Zugriff auf die private Eigenschaften einer Klasse entsprechende public Memberfunktionen definiert werden. Bei sehr kleinen Memberfunktionen, die z.B. nur eine Eigenschaft setzen oder zurückliefern, kann nun aber mehr Zeit für den Aufruf benötigt werden als für die Bearbeitung der Eigenschaft. Nachfolgend sind einmal die prinzipiellen Aktionen aufgeführt, die beim Aufruf einer Memberfunktion maximal durchgeführt werden. Hierbei haben die Aktionen 1,2,3,5 und 6 nicht direkt mit der gewünschten Funktionalität zu tun. Man bezeichnet dies auch als Overhead. Nur die Aktionen 4 und 7 sind eigentlich notwendig, um das gewünschte Ergebnis zu erhalten.  Und um diesen Overhead zur vermeiden, wurden die sogenannten inline-Funktionen bzw. inline-Memberfunktionen eingeführt.

  1. Parameter der Funktion bereitstellen, z.B. durch Ablage auf dem Stack oder in einem gesonderten Speicherbereich
  2. Rücksprungadresse auf dem Stack ablegen
  3. Sprung zur Memberfunktion
  4. Memberfunktion ausführen
  5. Rücksprung in die aufrufende Funktion
  6. Parameter aufräumen, z.B. durch Auslesen des Stacks oder Freigabe des gesonderten Speicherbereichs
  7. nächste Anweisung ausführen
HinweisDies die maximale Anzahl von Aktionen. Je nach Prozessortyp und Compiler können einige dieser Aktionen auch entfallen.

inline-Funktionen

Sehen wir uns zunächst die inline-Funktionen an. Inline-Funktionen werden prinzipiell genauso definiert wie normale Funktionen. Zusätzlich wird nun aber vor dem Returntyp der Funktion das Schlüsselwort inline gestellt.

PgmHeader
inline void CheckError(int err, char* pT)
{
   if (err)
   {
      cout << "Fehler: " << err << pT << endl;
      exit (err);
   }
}

Triff der Compiler dann beim Übersetzen auf den Aufruf einer inline-Funktion, so wird er versuchen, anstelle des Funktionsaufrufs direkt den Code der Funktion an die Aufrufstelle einzufügen. Und somit entfällt der komplette Overhead für den Aufruf.

Da nun anstelle des Funktionsaufrufs direkt der Funktionscode ins Programm eingefügt wird, empfiehlt es sich, nur kleine Funktionen als inline-Funktionen zu definieren, da ansonsten die Größe des Programms unter Umständen beträchtlich anwachsen kann.

Hinweisinline-Funktionen entsprechen von der Wirkungsweise her in etwa den Präprozessor-Makros (#define-Direktive). Der Hauptunterschied zu den Makros liegt darin, dass die Parameter bei inline-Funktionen typisiert sind und inline-Funktionen einen Rückgabewert haben.

inline-Memberfunktionen

Werden Memberfunktionen innerhalb einer Klasse definiert, so werden sie unter gewissen Bedingungen defaultmäßig als inline-Memberfunktion behandelt.

PgmHeader
// Klassendefinition
class Window
{
   string title;
   ...
 public:
   // defaultmässig inline-Memberfunktion!
   const string& GetTitle() const
   {
      return title;
   }
   ...
};

// main() Funktion
int main()
{
   Window myWin;
   ...
   cout << myWin.GetTitle() << endl;
   // wird compiliert zu:
   // cout << myWin.title << endl;
   ...
}

Wird eine Memberfunktion innerhalb einer Klasse nur deklariert, so kann sie bei ihrer Definition außerhalb der Klasse durch voranstellen des Schlüsselworts inline vor dem Returntyp ebenfalls als inline-Memberfunktion definiert werden.

PgmHeader
// Klassendefinition
class Window
{
   string title;
   ...
 public:
   const string& GetTitle() const;
   ...
};

// inline Definition
inline const string& Win::GetTitle() const
{
   return title;
}
AchtungAber Achtung! Sollten Sie die Klasse auf zwei Dateien aufgeteilt haben (eine Header-Datei mit der Klassendefinition und eine CPP-Datei mit den Definitionen der Memberfunktionen), so müssen die inline-Memberfunktionen immer mit in die Header-Datei aufgenommen werden damit der Compiler den einzusetzenden Code kennt.

Einschränkungen bei inline

Wie bereits erwähnt, bestehen bei inline-Funktionen bzw. Memberfunktionen gewisse Einschränkungen. So sind z.B. rekursive Funktionen (das sind Funktionen die sich selbst aufrufen) in der Regel nicht als inline-Funktionen zugelassen. Auch schließen einige Compiler bestimmte Anweisungen innerhalb von inline-Funktionen aus. Bei manchen Compilern sind dies fast alle Anweisungen, die irgendwelche Sprünge verursachen wie z.B. Schleifen. Enthält eine inline-Memberfunktion eine nicht zugelassene Anweisung, so wird die Funktion bzw. Memberfunktion nicht als inline betrachtet.

Womit wir auch schon beim nächsten und wichtigsten Punkt wären. Die Definition einer Memberfunktion als inline ist nur eine Bitte an den Compiler, die Funktion/Memberfunktion entsprechend einzubauen und keine zwingende Vorschrift.

Und zum Schluss ist noch anzumerken, dass moderne Compiler versuchen den Code eines Moduls so gut wie möglich zu optimieren. Und dazu gehört teilweise die eigenständige Definition einer Funktion als inline-Funktion wenn sie im gleichen Modul (CPP-Datei) verwendet wird. Aber wie so oft lässt sich auch hierbei sehr viel über entsprechende Einstellungen des Compilers einstellen. Hier hilft nur ein Blick ins Handbuch bzw. in die Online-Hilfe.