auto у C++У C++ ключове слово auto - це потужна можливість, запроваджена в C++11, яку використовують для оголошення змінних із виведеним типом даних.
Компілятор виводить тип змінної на основі її ініціалізатора, що може зробити код зрозумілішим і легшим у супроводі.
Розглянемо наступний приклад, де auto використовують для оголошення змінних:
auto dragon_population{3}; // dragon_population is deduced as an integer
auto westeros{7.7777}; // westeros is deduced as a double
auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string
У кожному випадку тип змінної виводиться зі значення, яким її ініціалізовано.
Ключове слово auto допомагає писати лаконічніший і зрозуміліший код, зменшуючи багатослівність явних типів.
const std::vector<std::string> pigeon_pie{"flour", "butter", "pigeon", "salt"};
auto purple_wedding_pie{pigeon_pie};
purple_wedding_pie.emplace_back("the strangler");
У цьому циклі auto виводить тип purple_wedding_pie як std::vector<std::string>, уникаючи потреби знову явно вказувати тип.
Ключове слово auto сумісне з різними конструкціями C++, що робить його універсальним інструментом у сучасному програмуванні на C++.
auto& element{array[0]}; // reference to an element
const auto object{otherObject}; // const type version of otherObject's type
auto* ptr{&x}; // pointer to x with the same type as x, but as a pointer.
У наступних концепціях ми часто будемо бачити ключове слово auto з лямбда-виразами, циклами for на основі діапазону та ітераторами.
Розумні вказівники - це сучасна можливість C++, покликана забезпечувати автоматичне керування памʼяттю, допомагаючи запобігати витокам памʼяті та завислим вказівникам, які зазвичай повʼязують із сирими вказівниками. Вони діють як обгортки навколо сирих вказівників, додаючи додаткову функціональність, як-от автоматичне звільнення памʼяті, коли вказівник більше не потрібен.
Розумні вказівники зазвичай реалізовані як шаблони класів у стандартній бібліотеці C++.
Два найпоширеніші розумні вказівники - це std::unique_ptr і std::shared_ptr.
std::unique_ptr - це розумний вказівник, який одноосібно володіє обʼєктом.
Він гарантує, що в будь-який момент лише один обʼєкт std::unique_ptr володіє ресурсом.
Коли std::unique_ptr, що володіє ресурсом, знищується або скидається, він автоматично знищує обʼєкти та звільняє його памʼять.
#include <memory>
// Declaring and defining a unique pointer
auto rightful_king_of_england = std::make_unique<std::string>("Excalibur");
// Unique pointers cannot be copied or assigned
auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr
std::make_unique()
Створюючи std::unique_ptr, краще використовувати std::make_unique() замість прямого використання new для виділення памʼяті.
std::make_unique() має кілька переваг:
std::make_unique() гарантує безпеку винятків.
Якщо під час конструювання обʼєкта виникає виняток, памʼять буде автоматично звільнено, що запобігає витокам памʼяті.std::make_unique() робить код яснішим і лаконічнішим.
Воно усуває потребу явно вказувати тип, що виділяється, оскільки аргументи шаблону виводяться автоматично.std::make_unique() ефективніше, ніж виділяти памʼять вручну за допомогою new, що може призвести до покращення продуктивності.std::unique_ptr сконструйовано вручну.
Це призведе до невизначеної поведінки, коли std::unique_ptr спробує видалити його в кінці своєї області видимості.std::shared_ptr - це розумний вказівник, який дозволяє кільком обʼєктам std::shared_ptr спільно володіти одним і тим самим ресурсом.
Він відстежує, скільки спільних вказівників посилаються на ресурс, і звільняє памʼять лише тоді, коли останній спільний вказівник, що володіє ресурсом, виходить з області видимості або скидається.
// Declaring and defining a shared pointer to a dynamically allocated string
auto martian_congressional_republic = std::make_shared<std::string>("protomolecule");
// Creating more shared pointer that shares ownership
auto outer_planets_alliance = martian_congressional_republic;
auto united_nations = martian_congressional_republic;
У C++17 і раніших версіях використання std::shared_ptr із масивами через std::make_shared<T[]> напряму не підтримується.
Хоча виділити масиви за допомогою std::make_shared<T[]> можливо, створення спільних вказівників безпосередньо з них може призвести до невизначеної поведінки через відмінності в керуванні памʼяттю між окремими обʼєктами та масивами.
Замість цього розглянемо використання std::vector або власних функцій видалення, щоб ефективно керувати масивами зі спільними вказівниками.
Завжди слід переконатися в сумісності зі своїм компілятором і реалізацією стандартної бібліотеки, коли маємо справу з виділенням масивів і спільними вказівниками в C++17.
std::make_shared()
Подібно до std::make_unique(), std::make_shared() пропонує переваги, як-от підвищена ефективність використання памʼяті, безпека винятків і зрозумілість.
Він поєднує виділення памʼяті для контрольного блоку та керованого обʼєкта в одну операцію, підвищуючи ефективність і зменшуючи ризик витоків памʼяті.
Крім того, автоматичне виведення аргументів шаблону спрощує код і підвищує зрозумілість.
Використання std::make_shared() сприяє чистішому, безпечнішому та ефективнішому коду під час роботи з обʼєктами std::shared_ptr у C++.
Типово використовуймо розумні вказівники: std::unique_ptr для одноосібного володіння, а std::shared_ptr для спільного володіння.
Залишаймо сирі вказівники для посилань без володіння або для взаємодії із застарілим кодом.
У більшості випадків std::unique_ptr достатньо для одноосібного володіння, оскільки він забезпечує легке керування памʼяттю без накладних витрат на підрахунок посилань.
std::shared_ptr слід використовувати ощадливо, оскільки він додає накладні витрати й складність, якщо тільки не потрібне справжнє спільне володіння.
Ця вправа запрошує нас у світ Трої. Життя її мешканців сповнене чудес і магії. Багато людей у Трої володіють силами, які вони часто використовують у повсякденному житті. Сили допомагають перетворювати світ або впливати на фауну Трої та інших людей. Магія також проявляється в унікальних артефактах, за якими полюють шукачі пригод, ремісники та мудреці.
У цій вправі ми напишемо код, який моделює людей Трої, артефакти, якими вони володіють, і взаємодію сил.
На нас чекає шість завдань. Перше стосується створення людини, а решта пʼять присвячені поводженню із силами та артефактами.
Для нашої моделі Трої найважливіше місце посідають люди. Модель людини повинна вміти володіти унікальним артефактом. Вона також повинна мати здатність проявляти силу. Ці сили можуть впливати на інших людей, тож нам також потрібно змоделювати, чи перебуває людина під впливом якоїсь іншої сили.
Нам надано базові реалізації структур artifact і power. Реалізуйте структуру (або клас) human, яка має змінну-член possession, що є розумним вказівником на artifact. Лише одна людина може володіти кожним артефактом у будь-який момент часу.
Структура human повинна мати ще дві змінні-члени. Одна зберігає own_power людини, а друга - силу, під впливом якої людина перебуває (influenced_by). І own_power, і influenced_by є розумними вказівниками на powers. Кожна power може належати одній людині, але водночас впливати й на інших людей.
Типово люди народжуються без артефактів, не мають власних сил і не перебувають під їхнім впливом.
human mindy_mccready{};
mindy_mccready.possession;
// => nullptr
mindy_mccready.own_power;
// => nullptr
mindy_mccready.influenced_by;
// => nullptr
Наша модель буде нудною без взаємодії її частин. Ми хочемо створювати унікальні артефакти й давати їх певним людям.
Визначте функцію give_new_artifact, яка нічого не повертає, але приймає посилання на human і string. За допомогою string вона повинна створити новий обʼєкт artifact і відповідно встановити вказівник possession у human. Функція не повинна нічого повертати.
human erik_magnus_lehnsherr{};
give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet");
erik_magnus_lehnsherr.possession->name;
// "Mind shielding helmet"
Світ Трої тримається на взаємодії. Ми хочемо, щоб люди торгували, обмінюючись тим, чим володіють.
Напишіть функцію exchange_artifacts, яка нічого не повертає, але приймає два розумні вказівники на артефакти, щоб обміняти їх. Памʼятаймо, що unique_ptr не можна копіювати. Це стосується і використання в параметрах функції. Натомість використайте посилання на unique_ptr.
human uchiha{};
give_new_artifact(uchiha, "konoha headband");
human uzumaki{};
give_new_artifact(uzumaki, "forehead protector");
exchange_artifacts(uchiha.possession, uzumaki.possession);
uchiha.possession->name;
// "forehead protector"
uzumaki.possession->name;
// "konoha headband"
Найзахопливіше в Трої - особливі сили, якими можуть володіти люди. Дехто вміє плавити залізо самою лише думкою, а інші здатні миттєво загоювати будь-які рани уночі.
Визначте функцію manifest_power, яка нічого не повертає, але приймає посилання на human і string. За допомогою string вона повинна створити новий обʼєкт power і відповідно встановити вказівник own_power у human. Функція не повинна нічого повертати.
human eleven {};
manifest_power(eleven, "psychokinesis");
eleven.own_power->effect;
// "psychokinesis"
Навіщо наймогутніші сили, якщо ними не можна скористатися? Наша модель зосереджена на людях, тож ми хочемо відстежувати вплив сил.
Напишіть функцію use_power з типом повернення void, яка приймає два посилання на людей. Перша людина застосовує силу, а друга стає її ціллю. Вказівник influenced_by цілі повинен указувати на силу того, хто її застосував.
Для простоти на людину може впливати лише одна сила. Ця сила залишається, навіть якщо того, хто її застосував, уже не існує.
human pamela_isley{};
manifest_power(pamela_isley, "control pheromones");
human count_vertigo{};
use_power(pamela_isley, count_vertigo);
count_vertigo.influenced_by->effect;
// "control pheromones"
Деякі сили втрачають свою дієвість або спричиняють певні ефекти в нашій симуляції, коли їх застосовують до кількох людей. Ми хочемо відстежувати кількість людей, повʼязаних із кожною силою.
Визначте функцію power_intensity, яка приймає human і повертає інтенсивність його сили як int. Якщо в людини немає сили, повернене значення повинно бути 0. Інакше інтенсивність повинна враховувати того, хто застосував силу, і всіх людей, які зараз під її впливом.
human jean_grey{};
manifest_power(jean_grey, "uplifting personality");
human scott{};
human logan{};
human ororo{};
use_power(jean_grey, ororo);
use_power(jean_grey, logan);
use_power(jean_grey, scott);
power_intensity(jean_grey);
// 4
Зареєструйтеся на Exercism, щоб вивчати й опановувати C++, а також 19 концепцій100 вправ та справжнє наставництво від людей, і все це безкоштовно.