← Back to C++ Course | Chapter 17: Advanced C++ | Lesson 17 of 17

C++ Interview Questions Advanced

These are harder questions asked in advanced C++ interviews, on topics like smart pointers and templates. Practicing them is like rehearsing before a big performance.

Smart Pointers and RAII

Smart pointers apply RAII (Resource Acquisition Is Initialization) to dynamic memory: std::unique_ptr enforces single ownership and frees its object automatically when it goes out of scope, while std::shared_ptr allows multiple owners via reference counting -- both eliminate the need to remember a manual delete.

Example: Smart Pointers and RAII

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Program execution starts in main()
int main() {
	// Use a unique_ptr: a smart pointer that owns the object and frees it automatically
	std::unique_ptr<int> ptr = std::make_unique<int>(5);
	// Print to the console with cout
	std::cout << *ptr << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Move Semantics and rvalue references

Move semantics lets an object's internal resources -- like a heap buffer -- be transferred from a temporary into a new object via pointer reassignment, rather than performing a full deep copy.

This is what makes returning large objects from functions cheap in modern C++.

Example: Move Semantics and rvalue references

cpp
// Include std::cout and std::cin
#include <iostream>
// Include std::vector
#include <vector>

// Program execution starts in main()
int main() {
	// Create a vector named source (a resizable array)
	std::vector<int> source = {1, 2, 3};
	// Create a vector named target (a resizable array)
	std::vector<int> target = std::move(source);
	// Print to the console with cout
	std::cout << target.size() << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Virtual Destructors

A base class intended to be deleted through a base-class pointer must declare its destructor virtual; otherwise, deleting a derived object through a base pointer only runs the base class's destructor, skipping the derived class's cleanup and leaking any resources it owns.

Example: Virtual Destructors

cpp
// Include std::cout and std::cin
#include <iostream>

// Define the type Base
class Base {
// Members below can be accessed from outside the class
public:
	virtual ~Base() { std::cout << "Base destroyed" << std::endl; }
};

// Define the type Derived
class Derived : public Base {
// Members below can be accessed from outside the class
public:
	~Derived() { std::cout << "Derived destroyed" << std::endl; }
};

// Program execution starts in main()
int main() {
	// Allocate an object on the heap with new
	Base *b = new Derived();
	// Free the heap memory with delete
	delete b;
	return 0;
}

SFINAE and Concepts

SFINAE ("Substitution Failure Is Not An Error") is a template-metaprogramming technique where an invalid template substitution is silently discarded from overload resolution rather than causing a compile error, letting templates constrain which types they accept.

C++20 Concepts formalize this into readable, explicit syntax.

Example: SFINAE and Concepts

cpp
// Include std::cout and std::cin
#include <iostream>
#include <type_traits>

// Declare a template so this works with any suitable type
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
show(T value) {
	// Print to the console with cout
	std::cout << "Integral: " << value << std::endl;
}

// Program execution starts in main()
int main() {
	show(5);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Perfect Forwarding and std::forward

Perfect forwarding, using std::forward inside a template function that takes universal references (T&&), preserves whether each argument was originally an lvalue or an rvalue as it's passed along to another function -- essential for generic wrapper functions that shouldn't accidentally force an unnecessary copy.

Example: Perfect Forwarding and std::forward

cpp
// Include std::cout and std::cin
#include <iostream>
#include <utility>

void process(int &x) { std::cout << "lvalue" << std::endl; }
void process(int &&x) { std::cout << "rvalue" << std::endl; }

// Declare a template so this works with any suitable type
template <typename T>
void wrapper(T &&arg) {
	process(std::forward<T>(arg));
}

// Program execution starts in main()
int main() {
	// Declare a and set it to 5
	int a = 5;
	wrapper(a);
	wrapper(10);
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Assuming shared_ptr and unique_ptr ownership are interchangeable, when unique_ptr allows only one owner.
  2. Using an object after calling std::move on it.
  3. Forgetting a virtual destructor in a base class used polymorphically.
Chapter Summary
  • Namespaces, header files, and multi-file programming organize larger projects.
  • The four cast operators, static_cast, dynamic_cast, const_cast, and reinterpret_cast, convert types in different ways.
  • Threads, mutexes and locks, async and future, debugging, input validation, mini projects, and interview questions apply C++ to real work.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.