P
prepair.app
Пройти інтерв'ю →
EnglishУкраїнськаРусский
🔷

Питання на співбесіді C++

Співбесіда з C++ перевіряє три речі: чи розумієте ви обʼєктну модель, чи можна довірити вам памʼять і чи знаєте ви, чого коштує стандартна бібліотека. Нижче питання, які ставлять найчастіше, кожне з еталонною відповіддю.

Junior · без досвіду / до 1 рокуMiddle · 2–4 роки досвідуSenior · 5+ років досвіду

Що запитують

Памʼять, вказівники та RAII
ООП, віртуальні функції та vtable
Move-семантика і правило пʼяти
Шаблони та метапрограмування
Контейнери STL і складності
Багатопотоковість і гонки даних

10 реальних питань з відповідями

До кожного питання — еталонна відповідь, з якою можна порівняти свою.

1

Чим вказівник відрізняється від посилання?

Відповідь

Посилання привʼязується при створенні й перепризначене бути не може; вказівник буває нульовим, перепризначається і має власну адресу та арифметику. На практиці посилання беруть, коли обʼєкт мусить існувати, а вказівник — коли відсутність є законним станом. Посилання не окремий обʼєкт, тому немає ні посилань на посилання, ні масивів із них.

2

Що таке RAII?

Відповідь

Захоплення ресурсу є ініціалізацією: ресурсом володіє обʼєкт, захоплення відбувається в конструкторі, звільнення — у деструкторі. Оскільки деструктори виконуються на всіх шляхах виходу, включно з розкруткою стека винятком, ресурс неможливо втратити через ранній return, який хтось додав пізніше. Усі розумні вказівники, лок-гарди і файлові потоки стандартної бібліотеки — це вона.

3

`unique_ptr`, `shared_ptr`, `weak_ptr` — коли що?

Відповідь

unique_ptr — одноосібне володіння, переміщується, але не копіюється, і не коштує нічого понад сирий вказівник: він має бути вибором за замовчуванням. shared_ptr — спільне володіння з атомарним лічильником посилань, це не безкоштовно і часто береться там, де володіння просто не було продумане. weak_ptr спостерігає за shared_ptr, не володіючи ним, і головна його робота — розривати цикли, які інакше ніколи не звільняться.

4

Навіщо базовому класу віртуальний деструктор?

Відповідь

Бо видалення похідного обʼєкта через вказівник на базовий без нього — невизначена поведінка, а на практиці деструктор нащадка просто не виконується і його поля витікають. Правило таке: якщо від класу збираються успадковуватися й видаляти поліморфно, деструктор віртуальний. Якщо клас не задуманий базовим, деструктор йому не потрібен, а доданий створює vtable, якої не було.

5

Що таке `vptr` і `vtable`?

Відповідь

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

6

Чим стек відрізняється від купи?

Відповідь

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

7

Що таке move-семантика і що робить `std::move`?

Відповідь

Move-семантика дозволяє передати ресурс замість копіювання: move-конструктор вектора забирає вказівник на буфер, а не виділяє памʼять і копіює елементи. Сам std::move нічого не переміщує — це зведення до rvalue-посилання, яке робить обʼєкт придатним для переміщення. Чи переміститься щось, залежить від наявності в типу move-конструктора, а обʼєкт-джерело лишається валідним, але з невизначеним вмістом.

8

Що таке невизначена поведінка і чим вона небезпечна?

Відповідь

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

9

Коли обирають `std::vector`, а коли `std::list`?

Відповідь

Майже завжди вектор. vector неперервний, тому обхід дружній до кешу і передвибірки, а list ганяється за вказівником на кожному елементі й платить виділення на вузол. list виграє лише коли ви постійно вставляєте в середину або сплайсите і тримаєте ітератори, які мусять лишатися валідними, — і навіть тоді варто поміряти, бо на сучасному залізі локальність зазвичай бʼє кращу асимптотику.

10

Що таке гонка даних і як її уникнути?

Відповідь

Два потоки звертаються до однієї комірки памʼяті, хоча б один пише, і між ними немає синхронізації — це невизначена поведінка, а не просто невірний результат. Уникають її, не розділяючи змінюваний стан, або захищаючи його мʼютексом, або роблячи доступ атомарним. ThreadSanitizer знаходить більшість таких місць, і це надійніше за міркування про розклад, який ви не можете відтворити.

🦎

Прочитати відповіді недостатньо

На співбесіді ти говориш вголос під тиском. Кем поставить ті самі питання, оцінить кожну відповідь і покаже, що саме підтягнути.

Пройти інтерв'ю C++ →
Безкоштовно · 3 інтерв'ю на місяць

Варто прочитати

Всі статті →

Інші спеціалізації

🔍QA Manual🤖QA AutomationJava Backend🐍Python Backend🐘PHP Backend🦫Go Backend🟢Node.js Backend💎Ruby on Rails🟨JavaScript⚛️React Frontend💚Vue Frontend🅰️Angular FrontendNext.js🍏iOS (Swift)🟩Android (Kotlin)⚙️DevOps / SRE🗄️Data Engineer📈Business Analyst🎯Product Manager📋Project Manager🎨UI/UX Designer📣Marketing