Сучасний C++ (C++11, C++14 і новіші) змінив підхід до написання програм, запровадивши можливості, які роблять код більш виразним, лаконічним і ефективним. У цьому пості ми розглянемо основні вправи, що охоплюють універсальну ініціалізацію, nullptr
, std::chrono
та потужний ключове слово auto
. Давайте писати код розумніше, а не важче! 💡
🔄 Універсальна ініціалізація: Прийміть фігурні дужки
Універсальна ініціалізація дозволяє ініціалізувати змінні однаковим чином, спрощуючи синтаксис і підвищуючи безпеку типів. Ось програма, яка це демонструє:
Код:
#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