🚀 Сучасний C++: Заглиблюємось у лямбда-функції, випадкові числа та розумні вказівники 🧠

Модерний C++ робить програмування чистішим, безпечнішим і ефективнішим. Цей блог проведе вас через лямбда-функції та локальні змінні, захоплення за допомогою переміщення, генерацію випадкових чисел і магію std::unique_ptr. Готові підняти свої навички C++ на новий рівень? Починаємо! 💡

pic

🔐 Лямбда-локальні змінні

У сучасному C++ лямбда-функції — це не просто легковажні анонімні функції; вони також дозволяють визначати локальні змінні всередині свого тіла.

Основні факти про лямбда-локальні змінні:

  1. Оголошення: Змінні в тілі лямбди не обов'язково повинні оголошуватись через auto, але можуть бути.
  2. Ініціалізація: Змінні повинні бути явно ініціалізовані перед використанням.

Приклад: Локальні змінні в лямбді

#include   

int main() {  
 auto myLambda = []() {  
 int localVar = 42; // Лямбда-локальна змінна  
 std::cout << "Лямбда-локальна змінна: " << localVar << "\n";  
 };  
 myLambda();  
 return 0;  
}

🧩 Основний висновок: Лямбда-локальні змінні обмежені до тіла лямбди, що забезпечує безпечне і ізольоване використання.

🧳 Ініціалізація лямбда-локальних змінних із захоплених змінних

Лямбда-функції можуть ініціалізувати свої локальні змінні за допомогою захоплених змінних.

Як захоплювати змінні:

  • Використовуйте [x] для захоплення за значенням.
  • Використовуйте [&x] для захоплення за посиланням.

Приклад: Захоплення і ініціалізація локальної змінної

#include   

int main() {  
 int base = 10;  
 auto myLambda = [base]() {  
 int localVar = base + 5; // Ініціалізація localVar за допомогою захопленої змінної  
 std::cout << "Base: " << base << ", Лямбда-локальна змінна: " << localVar << "\n";  
 };  
 myLambda();  
 return 0;  
}

📦 Захоплення за допомогою переміщення в лямбдах

Іноді ви хочете перемістити ресурси в лямбду, щоб уникнути копіювання. Використовуйте функцію std::move і захоплюйте змінну за значенням.

Приклад: Захоплення за допомогою переміщення

#include   
#include   
#include   

int main() {  
 std::string largeString = "This is a large string";  
 auto myLambda = [str = std::move(largeString)]() {  
 std::cout << "Захоплений рядок: " << str << "\n";  
 };  
 myLambda();  
 // largeString тепер порожній  
 std::cout << "Оригінальний рядок після переміщення: " << largeString << "\n";  
 return 0;  
}

🧩 Основний висновок: Захоплення за допомогою переміщення забезпечує ефективне передавання прав власності в лямбди, особливо для великих або не-копійованих об'єктів.

🎲 Генерація випадкових чисел

Модерний C++ надає бібліотеку `` для надійної генерації випадкових чисел.

Приклад: Випадкові цілі числа (від 0 до 100)

#include   
#include   

int main() {  
 std::random_device rd; // Джерело насіння  
 std::mt19937 gen(rd()); // Генератор Mersenne Twister  
 std::uniform_int_distribution<> distrib(0, 100);  
 for (int i = 0; i < 10; ++i) {  
 std::cout << distrib(gen) << " ";  
 }  
 return 0;  
}

Приклад: Випадкові числа з плаваючою комою (від 0 до 1)

#include   
#include   

int main() {  
 std::random_device rd;  
 std::mt19937 gen(rd());  
 std::uniform_real_distribution<> distrib(0.0, 1.0);  
 for (int i = 0; i < 10; ++i) {  
 std::cout << distrib(gen) << " ";  
 }  
 return 0;  
}

❌ Чому слід уникати локальних випадкових генераторів?

Використання випадкового генератора як локальної змінної ініціалізує його щоразу, що може призвести до передбачуваних або не оптимальних випадкових значень. Замість цього використовуйте глобальний або статичний генератор випадкових чисел для збереження стану між викликами.

🧠 Розуміння std::unique_ptr

Що таке std::unique_ptr?

  • Це смарт-вказівник, що володіє динамічно виділеним об'єктом.
  • Забезпечує звільнення ресурсу, коли unique_ptr виходить із області видимості.
  • Запобігає копіюванню (володіння не може бути спільним).

Ефективність проти сирих вказівників:

  1. Використання пам'яті: Немає додаткових витрат (лише вказівник).
  2. Ефективність: Автоматичне управління ресурсами, що запобігає витокам пам'яті.

RAII і std::unique_ptr:

RAII (Resource Acquisition Is Initialization) забезпечує автоматичне очищення ресурсів (наприклад, пам'яті).
std::unique_ptr є прикладом RAII, оскільки:

  • Перехоплює володіння під час ініціалізації.
  • Звільняє володіння при знищенні.

🛠️ Використання std::unique_ptr

Приклад: Базове використання

#include   
#include   

int main() {  
 std::unique_ptr ptr = std::make_unique(42); // Ініціалізація  
 std::cout << "Значення: " << *ptr << "\n";  
 // Переміщення володіння  
 std::unique_ptr newPtr = std::move(ptr);  
 std::cout << "Нове значення: " << *newPtr << "\n";  
 return 0;  
}

Сумісність з C++11:

  • Замість std::make_unique використовуйте std::unique_ptr(new int(42)).

🚀 Заключні думки

Модерні можливості C++, такі як лямбда-функції, генерація випадкових чисел і std::unique_ptr, роблять ваш код чистішим, безпечнішим і ефективнішим. Розуміючи та опановуючи ці інструменти, ви зможете писати високоякісні, підтримувані програми з легкістю.

by : Malinda Gamage

Перекладено з: 🚀 Modern C++: Diving Deeper into Lambdas, Random Numbers, and Smart Pointers 🧠

Leave a Reply

Your email address will not be published. Required fields are marked *