Урок №104. Передача по посиланню

  Юрій  | 

  Оновл. 18 Січ 2021  | 

 103

Хоча передача по значенню є хорошим варіантом для багатьох випадків, вона все ж має декілька обмежень.

По-перше, при передачі по значенню великої структури або класу в функцію, створюється копія аргументу і вже ця копія передається в параметр функції. Здебільшого це марна трата ресурсів, яка знижує продуктивність.

По-друге, при передачі аргументів по значенню, єдиний спосіб повернути значення назад в викликаючий об’єкт — це використовувати значення, що повертається (за допомогою оператора return) з функції. Але іноді трапляються ситуації, коли потрібно, щоб функція змінила значення переданого аргументу.

Передача по посиланню вирішує всі ці проблеми.

Передача по посиланню

При передачі змінної по посиланню потрібно просто оголосити параметри функції як посилання, а не як звичайні змінні:

При виклику функції змінна x стане посиланням на аргумент. Оскільки посилання на змінну обробляється точно так же, як і сама змінна, то будь-які зміни, внесені в посилання, призведуть до змін вихідного значення аргументу! У наступному прикладі це добре проілюстровано:

Ця програма точно така ж, як і програма з попереднього уроку, за винятком того, що параметром функції boo() тепер є посилання замість звичайної змінної.

Результат виконання програми:

value = 6
value = 7

Як ви можете бачити, функція змінила значення аргументу з 6 на 7!

Ось ще один приклад:

Результат виконання програми:

a = 7
a = 8

Зверніть увагу, значення аргументу a було змінено функцією.

Повернення відразу декількох значень

Іноді нам може знадобитися, щоб функція повертала відразу декілька значень. Однак оператор return дозволяє функції мати тільки одне значення, що повертається. Одним із способів повернення відразу декількох значень є використання посилань в якості параметрів:

Ця функція приймає один параметр (передача по значенню) в якості вхідних даних і «повертає» два параметри (передача по посиланню) в якості вихідних даних. Параметри, які використовуються тільки для повернення значень назад в caller, називаються параметрами виводу. Вони дають зрозуміти caller-у, що значення вихідних змінних, переданих у функцію, не настільки значні, так як ми очікуємо, що ці змінні будуть перезаписані.

Давайте розглянемо це детально. По-перше, в функції main() ми створюємо локальні змінні sin і cos. Вони передаються в функцію getSinCos() по посиланню (а не по значенню). Це означає, що функція getSinCos() має прямий доступ до початкових значень змінних sin і cos, а не до їх копій. Функція getSinCos(), відповідно, присвоює нові значення змінним sin і cos (через посилання sinOut і cosOut), перезаписуючи їх старі значення. Потім main() виводить ці оновлені значення.

Якби sin і cos були передані по значенню, а не по посиланню, то функція getSinCos() змінила б копії sin і cos, а не вихідні значення і ці зміни знищились би в кінці функції — змінні вийшли б з локальної області видимості. Але, оскільки sin і cos передавалися по посиланню, будь-які зміни, внесені в sin або cos (через посилання), зберігаються і за межами функції getSinCos(). Таким чином, ми можемо використовувати цей механізм для повернення відразу декількох значень назад в caller.

Хоча цей спосіб хороший, але він також має свої нюанси. По-перше, синтаксис трохи незвичний, оскільки параметри вводу і виводу вказуються разом з викликом функції. По-друге, в caller-і не очевидно, що sin і cos є параметрами виводу, і вони будуть змінені функцією. Це, ймовірно, найнебезпечніша частина даного способу передачі (так як може призвести до помилок). Деякі програмісти вважають це досить великою проблемою, і не радять передавати аргументи по посиланню, віддавши перевагу передачі по адресу, не змішуючи при цьому параметри вводу і виводу.

Особисто я не рекомендую змішувати параметри вводу і виводу саме з цієї причини, але якщо ви це робите, то обов’язково додавайте коментарі до коду, описуючи, що і як ви робите.

Неконстантні посилання можуть посилатися тільки на неконстантні l-values (наприклад, на неконстантні змінні), тому параметр-посилання не може прийняти аргумент, який є константним l-value або r-value (наприклад, літералом або результатом виразу).

Передача по константному посиланню

Одним з найголовніших недоліків передачі по значенню є те, що всі аргументи, передані по значенню, копіюються в параметри функції. Коли аргументами є великі структури або класи, то цей процес може зайняти багато часу. У випадку з передачею по посиланню ця проблема легко вирішується. Коли аргумент передається по посиланню, то створюється посилання на фактичний аргумент (що займає мінімальну кількість часу на виконання), і ніякого копіювання значень не відбувається. Це дозволяє передавати великі структури або класи з мінімальною затратою ресурсів.

Однак тут також можуть виникнути потенційні проблеми. Посилання дозволяють функції змінювати значення аргументів напряму, що небажано, якщо ми хочемо, щоб аргумент був доступний тільки для читання. Коли ми знаємо, що функція не повинна змінювати значення аргументу, але не хочемо використовувати передачу по значенню, кращим рішенням буде використовувати передачу по константному посиланню.

Ви вже знаєте, що константне посилання — це посилання на змінну, значення якої змінити через це ж посилання ніяк не вийде. Отже, якщо ми використовуємо константне посилання в якості параметру, то отримуємо 100% гарантію того, що функція не змінить аргумент!

Запустивши наступний фрагмент коду, ми отримаємо помилку компіляції:

Використання const корисно з наступних причин:

   Ми отримуємо гарантію від компілятора, що значення, які не повинні бути змінені — не зміняться (компілятор видасть помилку, якщо ми спробуємо зробити щось подібне тому, що було у вищенаведеному прикладі).

   Програміст, бачачи const, розуміє, що функція не змінить значення аргументу. Це може допомогти при відлагодженні програми.

   Ми не можемо передати константний аргумент в неконстантне посилання-параметр. Використання константного параметру гарантує, що ми зможемо передавати як неконстантні, так і константні аргументи в функцію.

   Константні посилання можуть приймати будь-які типи аргументів, включаючи l-values, константні l-values ​​і r-values.

Правило: При передачі аргументів по посиланню завжди використовуйте константні посилання, якщо вам не потрібно, щоб функція змінювала значення аргументів.

Плюси і мінуси передачі по посиланню

Плюси передачі по посиланню:

   Посилання дозволяють функції змінювати значення аргументу, що іноді корисно. В іншому випадку, для гарантії того, що функція не змінить значення аргументу, потрібно використовувати константні посилання.

   Оскільки при передачі по посиланню копіювання аргументів не відбувається, то цей спосіб набагато ефективніший і швидший за передачу по значенню, особливо при роботі з великими структурами або класами.

   Посилання можуть використовуватися для повернення відразу декількох значень з функції (через параметри виводу).

Мінуси передачі по посиланню:

   Важко визначити, чи є параметр, переданий по неконстантному посиланню, параметром вводу, параметром виводу чи того й іншого одночасно. Розумне використання const і суфікса Out для зовнішніх змінних вирішує цю проблему.

   По виклику функції неможливо визначити, чи буде аргумент змінений функцією чи ні. Аргумент, переданий по значенню або по посиланню, виглядає однаково. Ми можемо визначити спосіб передачі аргументу тільки переглянувши оголошення функції. Це може призвести до ситуації, коли програміст не відразу зрозуміє, що функція змінює значення аргументу.

Коли використовувати передачу по посиланню:

   при передачі структур або класів (використовуйте const, якщо потрібно тільки для читання);

   коли потрібно, щоб функція змінювала значення аргументу.

Коли не використовувати передачу по посиланню:

   при передачі фундаментальних типів даних (використовуйте передачу по значенню);

   при передачі звичайних масивів (використовуйте передачу по адресу).

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *