How to Pass a C++ Interview: Top Advanced-Level Questions
A C++ developer interview is always a challenge. While you likely know the basic questions (the difference between new and malloc, what a virtual destructor is), the advanced level requires a deep understanding of the language's internal workings. In this article, we will break down the key topics that will definitely come up in a technical interview for Middle and Senior positions. We won't just list the questions; we'll provide detailed answers with code examples.
1. Smart Pointers and Their Internal Implementation
Question: "Explain how std::unique_ptr differs from std::shared_ptr? How is the thread safety of the reference counter implemented?"
This is a classic. The interviewer wants to see that you understand not just the syntax, but also the semantics of resource ownership.
- std::unique_ptr — exclusive ownership. Not copyable, only movable. Ideal for resources with a single owner.
- std::shared_ptr — shared ownership. Uses a reference counter (control block). When the counter drops to zero, the resource is destroyed.
- std::weak_ptr — an "observer". Does not increment the reference counter. Used to break cyclic dependencies in
shared_ptr.
Advanced nuance: The reference counter in shared_ptr is thread-safe (atomic operations are used), but this does not make the managed object itself thread-safe. There are also two counters: strong references and weak references. As long as there is at least one weak reference, the control block is not deleted, even if the object has already been destroyed.
#include <memory>#include <iostream>
class Resource {public: Resource() { std::cout << "Resource acquired"; } ~Resource() { std::cout << "Resource destroyed"; } void doWork() { std::cout << "Working..."; }};
int main() { std::unique_ptr<Resource> uptr = std::make_unique<Resource>(); uptr->doWork(); // std::unique_ptr<Resource> uptr2 = uptr; // Compilation error! std::unique_ptr<Resource> uptr2 = std::move(uptr); // OK
std::shared_ptr<Resource> sptr1 = std::make_shared<Resource>(); std::shared_ptr<Resource> sptr2 = sptr1; // Reference count = 2 sptr1.reset(); // Count = 1 sptr2.reset(); // Count = 0, object destroyed return 0;}2. Virtual Tables (vtable) and the Mechanism of Late Binding
Question: "How does a virtual function work at the memory level? Where is the vtable stored?"
This question tests understanding not only of polymorphism but also of memory layout in C++.
- For each class that has at least one virtual function, the compiler creates a static table (vtable). It contains pointers to virtual functions.
- Each object of such a class contains a hidden pointer
__vptr, which points to its class's vtable. - When a virtual function is called through a pointer or reference, the compiler generates code that goes through
__vptrto the vtable, finds the required function by offset, and calls it. - The vtable is stored in static memory (like a global variable), not on the stack or heap.
Advanced nuance: Complications with multiple inheritance. In this case, an object may have several __vptr pointers, and thunk functions (adjusting the this pointer) become necessary. This is one reason why multiple inheritance in C++ is considered dangerous and slow.
#include <iostream>
class Base {public: virtual void foo() { std::cout << "Base::foo"; } virtual ~Base() = def