C++ надає вбудовані функції, щоб зменшити витрати на виклики функцій. Вбудована функція — це функція, яка під час виклику розгортається в рядку. Під час виклику вбудованої функції весь код вбудованої функції вставляється або замінюється в точці виклику вбудованої функції. Ця заміна виконується компілятором C++ під час компіляції. Вбудована функція може збільшити ефективність, якщо вона мала.
Синтаксис:
inline return-type function-name(parameters) { // function code }>
Пам’ятайте, що інлайнінг – це лише запит до компілятора, а не команда. Компілятор може проігнорувати запит на вбудовування.
Компілятор може не виконувати інлайнінг за таких обставин, як:
- Якщо функція містить цикл. ( for, while і do-while )
- Якщо функція містить статичні змінні.
- Якщо функція рекурсивна.
- Якщо тип повернення функції інший, ніж void, і оператор return не існує в тілі функції.
- Якщо функція містить оператор switch або goto.
Чому використовуються вбудовані функції?
Коли програма виконує інструкцію виклику функції, ЦП зберігає адресу пам’яті інструкції, що йде після виклику функції, копіює аргументи функції в стек і, нарешті, передає керування вказаній функції. Потім ЦП виконує код функції, зберігає значення, що повертається функцією, у попередньо визначеному місці пам’яті/реєстрі та повертає керування функції, що викликає. Це може стати накладним, якщо час виконання функції менший за час перемикання від функції, що викликає, до функції, що викликається (викликається).
Для функцій, які є великими та/або виконують складні завдання, накладні витрати на виклик функції зазвичай незначні порівняно з кількістю часу, необхідного для виконання функції. Однак для невеликих, часто використовуваних функцій час, необхідний для здійснення виклику функції, часто набагато більше, ніж час, необхідний для фактичного виконання коду функції. Ці накладні витрати виникають для невеликих функцій, оскільки час виконання невеликої функції менший за час перемикання.
Вбудовані функції Переваги:
- Накладні витрати на виклик функції не виникають.
- Це також зберігає накладні витрати на змінні push/pop у стеку під час виклику функції.
- Це також заощаджує накладні витрати на зворотний виклик від функції.
- Коли ви вбудовуєте функцію, ви можете дозволити компілятору виконувати контекстно-залежну оптимізацію тіла функції. Такі оптимізації неможливі для звичайних викликів функцій. Інші оптимізації можна отримати, розглядаючи потоки контексту виклику та контексту виклику.
- Вбудована функція може бути корисною (якщо вона невелика) для вбудованих систем, оскільки вбудована функція може давати менше коду, ніж функція під назвою preamble і return.
Inline функція Недоліки:
- Додані змінні з вбудованої функції споживають додаткові регістри. Якщо після вбудованої функції кількість змінної, яка використовуватиме регістр, збільшується, вони можуть створити накладні витрати на використання ресурсу змінної реєстру. Це означає, що коли тіло вбудованої функції замінюється в точці виклику функції, також вставляється загальна кількість змінних, які використовує функція. Отже, кількість регістрів, які будуть використовуватися для змінних, також буде збільшено. Отже, якщо після вбудовування функції числа змінних різко збільшаться, це, безперечно, спричинить накладні витрати на використання реєстру.
- Якщо ви використовуєте занадто багато вбудованих функцій, розмір двійкового виконуваного файлу буде великим через дублювання того самого коду.
- Занадто велика кількість вбудованих елементів також може зменшити частоту звернення до кешу інструкцій, таким чином зменшуючи швидкість вибору інструкцій із кеш-пам’яті до основної пам’яті.
- Вбудована функція може збільшити витрати часу на компіляцію, якщо хтось змінить код усередині вбудованої функції, тоді все місце виклику має бути перекомпільоване, оскільки компілятор повинен буде ще раз замінити весь код, щоб відобразити зміни, інакше він продовжить роботу зі старим функціональність.
- Вбудовані функції можуть бути некорисними для багатьох вбудованих систем. Оскільки у вбудованих системах розмір коду важливіший за швидкість.
- Вбудовані функції можуть спричинити збій, оскільки вбудовування може збільшити розмір двійкового виконуваного файлу. Збиток пам'яті призводить до зниження продуктивності комп'ютера. Наступна програма демонструє використання вбудованої функції.
приклад:
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;> }> |
>
>Вихід
The cube of 3 is: 27>
Вбудовані функції та класи
Також можна визначити вбудовану функцію всередині класу. Насправді всі функції, визначені всередині класу, є неявно вбудованими. Таким чином, тут також застосовуються всі обмеження вбудованих функцій. Якщо вам потрібно явно оголосити вбудовану функцію в класі, тоді просто оголосите функцію всередині класу та визначте її поза класом за допомогою ключового слова inline.
Синтаксис:
class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };> Наведений вище стиль вважається поганим стилем програмування. Найкращий стиль програмування — це просто написати прототип функції всередині класу та вказати його як вбудований елемент у визначенні функції.
Наприклад:
class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }> приклад:
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>> a;> >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;> }> |
>
isletter java
>
Вихід:
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>
Що не так з макросом?
Читачі, знайомі з мовою Сі, знають, що мова Сі використовує макроси. Препроцесор замінює всі виклики макросу безпосередньо в коді макросу. Рекомендується завжди використовувати вбудовану функцію замість макросу. За словами доктора Б’ярна Страуструпа, творець C++ макроси майже ніколи не потрібні в C++, і вони схильні до помилок. Є деякі проблеми з використанням макросів у C++. Макрос не може отримати доступ до приватних членів класу. Макроси виглядають як виклики функцій, але насправді ними не є.
приклад:
C++
// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };> |
>
>
Вихід:
Error: '::' may not appear in macro parameter list #define MAC(S::m)>
Компілятор C++ перевіряє типи аргументів вбудованих функцій і необхідні перетворення виконуються правильно. Макрос препроцесора не може це зробити. Ще одна річ полягає в тому, що макросами керує препроцесор, а вбудованими функціями керує компілятор C++. Пам’ятайте: це правда, що всі функції, визначені всередині класу, є неявно вбудованими, і компілятор C++ виконуватиме вбудовані виклики цих функцій, але компілятор C++ не може виконувати вбудовані функції, якщо функція віртуальна. Причина виклику віртуальної функції вирішується під час виконання, а не під час компіляції. Віртуальний означає очікування до часу виконання, а вбудований означає під час компіляції, якщо компілятор не знає, яка функція буде викликана, як він може виконати інлайнінг? Ще одна річ, про яку слід пам’ятати, полягає в тому, що корисно робити функцію вбудованою, лише якщо час, витрачений під час виклику функції, перевищує час виконання тіла функції.
Приклад, коли вбудована функція взагалі не впливає:
inline void show() { cout << 'value of S = ' << S << endl; }> Виконання вищезазначеної функції займає досить багато часу. Загалом, функцію, яка виконує операцію введення-виведення (I/O), не слід визначати як вбудовану, оскільки вона витрачає значну кількість часу. Технічно вбудовування функції show() має обмежену цінність, оскільки кількість часу, який займе оператор вводу-виводу, значно перевищує накладні витрати на виклик функції. Залежно від компілятора, який ви використовуєте, компілятор може показати вам попередження, якщо функція не розгортається всередині.
Такі мови програмування, як Java та C#, не підтримують вбудовані функції. Але в Java компілятор може виконувати інлайнінг під час виклику методу small final, оскільки підкласи не можуть замінити фінальні методи, а виклик методу final вирішується під час компіляції.
У C# JIT-компілятор також може оптимізувати код, вставляючи невеликі виклики функцій (наприклад, замінюючи тіло невеликої функції, коли вона викликається в циклі). Останнє, про що слід пам’ятати, це те, що вбудовані функції є цінною особливістю C++. Відповідне використання вбудованих функцій може забезпечити підвищення продуктивності, але якщо вбудовані функції використовуються довільно, вони не можуть забезпечити кращих результатів. Іншими словами, не чекайте кращої продуктивності програми. Не робіть кожну функцію вбудованою. Краще, щоб вбудовані функції були якомога меншими.