C++ biedt inline-functies om de overhead van functieaanroepen te verminderen. Een inline-functie is een functie die in de regel wordt uitgebreid wanneer deze wordt aangeroepen. Wanneer de inline-functie wordt aangeroepen, wordt de volledige code van de inline-functie ingevoegd of vervangen op het punt van de inline-functie-aanroep. Deze vervanging wordt tijdens het compileren uitgevoerd door de C++-compiler. Een inline-functie kan de efficiëntie verhogen als deze klein is.
Syntaxis:
inline return-type function-name(parameters) { // function code }>
Houd er rekening mee dat inlining slechts een verzoek aan de compiler is en geen opdracht. De compiler kan het verzoek om inlining negeren.
Het is mogelijk dat de compiler geen inlining uitvoert in de volgende omstandigheden:
- Als een functie een lus bevat. ( voor, terwijl en doe-terwijl )
- Als een functie statische variabelen bevat.
- Als een functie recursief is.
- Als een functieretourtype anders is dan void en de return-instructie niet bestaat in de hoofdtekst van een functie.
- Als een functie een switch- of goto-instructie bevat.
Waarom worden inline-functies gebruikt?
Wanneer het programma de functieaanroepinstructie uitvoert, slaat de CPU het geheugenadres op van de instructie die volgt op de functieaanroep, kopieert de argumenten van de functie op de stapel en draagt uiteindelijk de besturing over aan de opgegeven functie. De CPU voert vervolgens de functiecode uit, slaat de functieretourwaarde op in een vooraf gedefinieerde geheugenlocatie/register en geeft de besturing terug aan de aanroepende functie. Dit kan overhead worden als de uitvoeringstijd van de functie korter is dan de schakeltijd van de aanroepende functie naar de aangeroepen functie (callee).
Voor functies die groot zijn en/of complexe taken uitvoeren, is de overhead van de functieaanroep doorgaans onbeduidend in vergelijking met de hoeveelheid tijd die het kost om de functie uit te voeren. Voor kleine, veelgebruikte functies is de tijd die nodig is om de functieaanroep te doen echter vaak veel langer dan de tijd die nodig is om de code van de functie daadwerkelijk uit te voeren. Deze overhead treedt op bij kleine functies omdat de uitvoeringstijd van een kleine functie korter is dan de schakeltijd.
Inline-functies Voordelen:
- Er vindt geen overhead van functieaanroepen plaats.
- Het bespaart ook de overhead van push/pop-variabelen op de stapel wanneer een functie wordt aangeroepen.
- Het bespaart ook de overhead van een retouroproep van een functie.
- Wanneer u een functie inline zet, kunt u de compiler in staat stellen contextspecifieke optimalisatie uit te voeren op de hoofdtekst van de functie. Dergelijke optimalisaties zijn niet mogelijk voor normale functieaanroepen. Andere optimalisaties kunnen worden verkregen door rekening te houden met de stromen van de aanroepende context en de opgeroepen context.
- Een inline-functie kan nuttig zijn (als deze klein is) voor ingebedde systemen, omdat inline minder code kan opleveren dan de functie preamble en return.
Inline-functie Nadelen:
- De toegevoegde variabelen van de inline-functie verbruiken extra registers. Als na de in-line-functie het variabelenummer dat het register gaat gebruiken toeneemt, kunnen ze overhead veroorzaken bij het gebruik van registervariabelen. Dit betekent dat wanneer de inline-functietekst wordt vervangen op het punt van de functieaanroep, het totale aantal variabelen dat door de functie wordt gebruikt, ook wordt ingevoegd. Het aantal registers dat voor de variabelen zal worden gebruikt, zal dus ook toenemen. Dus als de aantallen variabelen na functie-inlining drastisch toenemen, zou dit zeker overhead veroorzaken bij het registergebruik.
- Als u te veel inline-functies gebruikt, zal de grootte van het binaire uitvoerbare bestand groot zijn, vanwege de duplicatie van dezelfde code.
- Te veel inlining kan ook de hitrate van uw instructiecache verminderen, waardoor de snelheid waarmee instructies worden opgehaald van die van het cachegeheugen naar die van het primaire geheugen wordt verminderd.
- De inline-functie kan de overhead bij het compileren vergroten als iemand de code binnen de inline-functie wijzigt, dan moet de hele aanroeplocatie opnieuw worden gecompileerd omdat de compiler alle code opnieuw zou moeten vervangen om de wijzigingen weer te geven, anders gaat het door met de oude functionaliteit.
- Inline-functies zijn mogelijk niet nuttig voor veel embedded systemen. Omdat in embedded systemen codegrootte belangrijker is dan snelheid.
- Inline-functies kunnen thrashing veroorzaken, omdat inlining de grootte van het binaire uitvoerbare bestand kan vergroten. Het slaan in het geheugen zorgt ervoor dat de prestaties van de computer afnemen. Het volgende programma demonstreert het gebruik van de inline-functie.
Voorbeeld:
C++
#include> using> namespace> std;> inline> int> cube(>int> s) {>return> s * s * s; }> int> main()> {> >cout <<>'The cube of 3 is: '> << cube(3) <<>'
'>;> >return> 0;> }> |
>
>Uitvoer
The cube of 3 is: 27>
Inline-functie en klassen
Het is ook mogelijk om de inline-functie binnen de klasse te definiëren. In feite zijn alle functies die binnen de klasse zijn gedefinieerd impliciet inline. Alle beperkingen van inline-functies worden hier dus ook toegepast. Als u expliciet een inline-functie in de klasse wilt declareren, declareert u de functie gewoon binnen de klasse en definieert u deze buiten de klasse met behulp van het inline-trefwoord.
Syntaxis:
class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };> De bovenstaande stijl wordt beschouwd als een slechte programmeerstijl. De beste programmeerstijl is om gewoon het prototype van de functie binnen de klasse te schrijven en dit als inline in de functiedefinitie te specificeren.
Bijvoorbeeld:
class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }> Voorbeeld:
C++
// C++ Program to demonstrate inline functions and classes> #include> using> namespace> std;> class> operation {> >int> a, b, add, sub, mul;> >float> div>;> public>:> >void> get();> >void> sum();> >void> difference();> >void> product();> >void> division();> };> inline> void> operation ::get()> {> >cout <<>'Enter first value:'>;> >cin>> een;> >cout <<>'Enter second value:'>;> >cin>> b;> }> inline> void> operation ::sum()> {> >add = a + b;> >cout <<>'Addition of two numbers: '> << a + b <<>'
'>;> }> inline> void> operation ::difference()> {> >sub = a - b;> >cout <<>'Difference of two numbers: '> << a - b <<>'
'>;> }> inline> void> operation ::product()> {> >mul = a * b;> >cout <<>'Product of two numbers: '> << a * b <<>'
'>;> }> inline> void> operation ::division()> {> >div> = a / b;> >cout <<>'Division of two numbers: '> << a / b <<>'
'>;> }> int> main()> {> >cout <<>'Program using inline function
'>;> >operation s;> >s.get();> >s.sum();> >s.difference();> >s.product();> >s.division();> >return> 0;> }> |
>
metselaar formule
>
Uitgang:
Enter first value: 45 Enter second value: 15 Addition of two numbers: 60 Difference of two numbers: 30 Product of two numbers: 675 Division of two numbers: 3>
Wat is er mis met de macro?
Lezers die bekend zijn met de C-taal weten dat de C-taal macro gebruikt. De preprocessor vervangt alle macro-oproepen rechtstreeks binnen de macrocode. Het wordt aanbevolen om altijd de inline-functie te gebruiken in plaats van de macro. Volgens Dr. Bjarne Stroustrup, de maker van C++, zijn macro's bijna nooit nodig in C++ en zijn ze foutgevoelig. Er zijn enkele problemen met het gebruik van macro's in C++. Macro heeft geen toegang tot privéleden van de klas. Macro's zien eruit als functieaanroepen, maar zijn dat in werkelijkheid niet.
Voorbeeld:
C++
// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };> |
>
>
Uitgang:
Error: '::' may not appear in macro parameter list #define MAC(S::m)>
De C++-compiler controleert de argumenttypen van inline-functies en noodzakelijke conversies worden correct uitgevoerd. De preprocessor-macro kan dit niet doen. Een ander ding is dat de macro's worden beheerd door de preprocessor en inline-functies worden beheerd door de C++-compiler. Onthoud: het is waar dat alle functies die binnen de klasse zijn gedefinieerd impliciet inline zijn en dat de C++-compiler inline-aanroepen van deze functies zal uitvoeren, maar de C++-compiler kan niet inline uitvoeren als de functie virtueel is. De reden waarom een virtuele functie wordt aangeroepen, wordt tijdens runtime opgelost in plaats van tijdens het compileren. Virtueel betekent wachten tot runtime en inline betekent tijdens het compileren: als de compiler niet weet welke functie zal worden aangeroepen, hoe kan hij dan inlining uitvoeren? Een ander ding om te onthouden is dat het alleen nuttig is om de functie inline te maken als de tijd die wordt besteed aan een functieaanroep groter is dan de uitvoeringstijd van de functietekst.
Een voorbeeld waarbij de inline-functie helemaal geen effect heeft:
inline void show() { cout << 'value of S = ' << S << endl; }> Het duurt relatief lang om de bovenstaande functie uit te voeren. Over het algemeen mag een functie die een invoer-uitvoer (I/O)-bewerking uitvoert, niet als inline worden gedefinieerd, omdat deze een aanzienlijke hoeveelheid tijd in beslag neemt. Technisch gezien is het inlinen van de functie show() van beperkte waarde, omdat de hoeveelheid tijd die de I/O-instructie in beslag neemt veel groter is dan de overhead van een functieaanroep. Afhankelijk van de compiler die u gebruikt, kan de compiler u een waarschuwing tonen als de functie niet inline is uitgebreid.
Programmeertalen zoals Java en C# ondersteunen geen inline-functies. Maar in Java kan de compiler inlining uitvoeren wanneer de kleine definitieve methode wordt aangeroepen, omdat definitieve methoden niet door subklassen kunnen worden overschreven en de aanroep naar een definitieve methode tijdens het compileren wordt opgelost.
In C# kan de JIT-compiler ook code optimaliseren door kleine functieaanroepen inline te plaatsen (zoals het vervangen van de hoofdtekst van een kleine functie wanneer deze in een lus wordt aangeroepen). Het laatste dat u in gedachten moet houden is dat inline-functies een waardevol kenmerk van C++ zijn. Het juiste gebruik van inline-functies kan prestatieverbetering opleveren, maar als inline-functies willekeurig worden gebruikt, kunnen ze geen betere resultaten opleveren. Met andere woorden, verwacht geen betere prestaties van het programma. Maak niet elke functie inline. Het is beter om inline-functies zo klein mogelijk te houden.