🖥️ Досліджуємо сучасний C++: універсальна ініціалізація, nullptr, std::chrono та потужність auto

Сучасний C++ (C++11, C++14 і новіші) змінив підхід до написання програм, запровадивши можливості, які роблять код більш виразним, лаконічним і ефективним. У цьому пості ми розглянемо основні вправи, що охоплюють універсальну ініціалізацію, nullptr, std::chrono та потужний ключове слово auto. Давайте писати код розумніше, а не важче! 💡

pic

🔄 Універсальна ініціалізація: Прийміть фігурні дужки

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

Код:

#include   
#include   
#include   

int main() {  
 int x{7}; // Універсальна ініціалізація для int  
 std::string str{"Let us begin"}; // Універсальна ініціалізація для string  

 // int y{7.7}; // Якщо розкоментувати, виникне помилка компіляції  
 int y = 7.7; // Традиційна ініціалізація  

 std::cout << "x: " << x << "\n";  
 std::cout << "str: " << str << "\n";  
 std::cout << "y: " << y << "\n";  

 // Універсальна ініціалізація зі std::vector  
 std::vector vec{4, 2, 3, 5, 1};  
 std::cout << "vec: ";  
 for (int v : vec) std::cout << v << " ";  
 std::cout << "\n";  

 return 0;  
}

Чому виникає помилка?

  • Оголошення int y{7.7}; не проходить, оскільки універсальна ініціалізація не дозволяє звуження типів. Для таких випадків потрібно використовувати =.

🧩 Ключовий висновок: Універсальна ініціалізація забезпечує більш жорстку безпеку типів порівняно з традиційною ініціалізацією.

🧩 Розуміння nullptr: Сучасний вказівник на порожнє значення

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

Код:

#include   

void func(int val) {  
 std::cout << "Перевантаження для цілих чисел: " << val << "\n";  
}  

void func(int* ptr) {  
 if (ptr)  
 std::cout << "Перевантаження для вказівників: " << *ptr << "\n";  
 else  
 std::cout << "Перевантаження для вказівників: nullptr\n";  
}  

int main() {  
 func(NULL); // Амбігудність (у старих компіляторах може бути розв’язано як int)  
 func(nullptr); // Однозначно вирішується для перевантаження вказівника  

 return 0;  
}

Спостереження:

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

🧩 Ключовий висновок: Завжди використовуйте nullptr для ініціалізації вказівників у сучасному C++.

⏱️ Використання std::chrono: Інтервали часу

З допомогою std::chrono виразити інтервали часу стає інтуїтивно зрозумілим. Давайте визначимо інтервали, використовуючи синтаксис як C++11, так і C++14.

Синтаксис C++11:

#include   

auto interval1 = std::chrono::seconds(2); // 2 секунди  
auto interval2 = std::chrono::milliseconds(20); // 20 мілісекунд  
auto interval3 = std::chrono::microseconds(50); // 50 мікросекунд

Синтаксис C++14:

using namespace std::chrono_literals;  

auto interval1 = 2s; // 2 секунди  
auto interval2 = 20ms; // 20 мілісекунд  
auto interval3 = 50us; // 50 мікросекунд

🧩 Ключовий висновок: Літерали C++14 роблять операції з std::chrono ще більш виразними.
Використовуйте їх щораз, коли це можливо, для кращої читабельності!

🤖 Автоматичне визначення типів за допомогою auto

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

Приклад 1:

auto var = 6; // Компільтор визначає тип як int  
std::cout << "Тип змn";

Приклад 2: Ітератор до першого елемента:

#include   
#include   

std::vector words{"hello", "world"};  
auto it = words.begin(); // Тип визначається як std::vector::iterator  
// Традиційний синтаксис:  
std::vector::iterator it2 = words.begin();

🧩 Ключовий висновок: auto спрощує код, але його слід використовувати обачно, щоб зберегти ясність.

🔄 Цикли та ітератори: auto спрощує все

Традиційний цикл з ітератором:

std::vector vec{4, 2, 5, 3, 1};  
// Додаємо 2 до кожного елемента  
for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) {  
 *it += 2;  
}  
// Виводимо елементи  
for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) {  
 std::cout << *it << " ";  
}

Використання auto:

for (auto it = vec.begin(); it != vec.end(); ++it) {  
 *it += 2;  
}  

for (auto it = vec.begin(); it != vec.end(); ++it) {  
 std::cout << *it << " ";  
}

Цикл на основі діапазону:

for (auto& element : vec) {  
 element += 2;  
}  

for (const auto& element : vec) {  
 std::cout << element << " ";  
}

🧩 Ключовий висновок: Поєднуйте auto з циклами на основі діапазону для чистішого та виразнішого коду.

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

Сучасний C++ спрямований на написання чистішого, безпечнішого та ефективнішого коду. Такі можливості, як універсальна ініціалізація, nullptr, std::chrono і auto, роблять програмування інтуїтивно зрозумілим і приємним. Заглиблюйтесь у ці можливості, щоб підвищити рівень своїх навичок у C++! 🎯

by : Malinda Gamage

Перекладено з: 🖥️ Exploring Modern C++: Universal initialization, nullptr, std::chrono, and the power of auto

Leave a Reply

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