Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About Google hiring for C++ roles
Google, part of Alphabet, builds products such as Search, YouTube, Android, Google Cloud, Maps and Pay. Its Indian offices contribute to engineering, cloud, payments and research work for local and global products. It hires in India for software engineers, test and reliability engineers, data scientists and analysts who work on large-scale data and experimentation.
For C++ roles, this Google practice set focuses most on Multithreading and Concurrency (7), Standard Template Library (STL) (5), Pointers and Memory Management (4), Templates and Generic Programming (4). It has 1 easy, 23 medium, 6 hard questions, so you can start easy and work up to the harder ones.
Company type
Product
Headquarters
Mountain View, California, USA
Main India offices
Bengaluru, Hyderabad, Gurugram, Mumbai, Pune
Google C++ interview process
Recruiter screening
Online coding assessment or phone screen
Technical interviews (coding, 3-4 rounds)
Googleyness and leadership round
Hiring committee review
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for GoogleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
✓ 3 questions free • Unlock the rest in seconds
01
Write a program where two threads print odd and even numbers alternately up to 10.
If ordering is not needed, switch to std::unordered_map and call reserve with the expected size to avoid rehashing. For string keys, use heterogeneous lookup with string_view to avoid building temporary strings. If keys are fixed after loading, a sorted vector with binary search is very cache friendly. I would profile before and after, because hashing long strings has its own cost.
03
Should a Car class inherit from Engine or contain an Engine? Explain your choice.
A car is not an engine, it has an engine, so composition is correct: class Car holds an Engine member or a unique_ptr<Engine>. Inheritance models an is-a relationship and exposes the base interface, which would let callers treat a Car as an Engine. Composition also allows swapping engine types at run time through an interface such as PetrolEngine or ElectricMotor and keeps coupling low.
04
A service occasionally freezes and thread dumps show two threads each waiting on a mutex held by the other. How do you fix it?
This is a lock-order deadlock. I would find the two code paths, for example transfer locking account A then B while another locks B then A. The fix is to lock both together with std::scoped_lock(a.m, b.m), or to define a global ordering such as by account ID and always lock lower first. I would also shrink critical sections and add a stress test, and consider TSan or lock hierarchy checks.
05
Two objects hold shared_ptr references to each other and their memory is never released. Why, and how do you fix it?
This is a reference cycle. Each object keeps the other's reference count above zero, so neither destructor runs even after all outside pointers are gone. Fix it by making one direction non-owning, usually the back pointer, with weak_ptr. For example, a parent holds shared_ptr to its children, while each child holds a weak_ptr to the parent and calls lock() when it needs access.
constexpr unsigned long long factorial(unsigned n) {
unsigned long long r = 1;
for (unsigned i = 2; i <= n; ++i) r *= i;
return r;
}
static_assert(factorial(5) == 120);
constexpr auto f10 = factorial(10); // computed by the compiler
// Pre-C++14 style used template recursion:
// template <unsigned N> struct Fact { static const unsigned long long v = N * Fact<N - 1>::v; };
// template <> struct Fact<0> { static const unsigned long long v = 1; };
10
Your program gives correct output in a debug build but wrong output in a release build. How do you investigate?
This usually means undefined behaviour or an uninitialised variable that the optimiser exploits. I would compile with -Wall -Wextra and fix every warning, then run tests with -fsanitize=address,undefined to catch out-of-bounds access, overflow and use-after-free. ThreadSanitizer checks for data races. Building with -O2 -g lets me debug the optimised code, and bisecting functions or adding assertions narrows down the faulty spot.
11
Write a function that allocates a 2D matrix safely without raw new and delete.
#include <future>
#include <numeric>
#include <vector>
long long parallelSum(const std::vector<int>& v, int parts = 4) {
std::vector<std::future<long long>> futs;
std::size_t chunk = v.size() / parts;
for (int i = 0; i < parts; ++i) {
auto b = v.begin() + i * chunk;
auto e = (i == parts - 1) ? v.end() : b + chunk;
futs.push_back(std::async(std::launch::async, [b, e] {
return std::accumulate(b, e, 0LL);
}));
}
long long total = 0;
for (auto& f : futs) total += f.get();
return total;
}
// C++17 alternative: std::reduce(std::execution::par, v.begin(), v.end(), 0LL)
14
Design a producer-consumer pipeline where one thread reads log lines and several workers parse them.
I would use a bounded thread-safe queue built with a mutex and two condition variables, one for not empty and one for not full, so a fast reader cannot exhaust memory. The reader pushes lines and workers pop and parse them. For shutdown, the reader pushes a sentinel per worker or sets a closed flag and notifies all. Batching lines per push reduces locking overhead, and results go to a second queue.
15
A generic maxOf template gives wrong results when called with two C-style string literals. Why, and how do you fix it?
T is deduced as const char*, so the template compares pointer addresses instead of the characters. The result depends on where the literals are stored. Fix it by adding an overload for const char* that uses std::strcmp, or better, call it with std::string or std::string_view, where operator< compares contents. This shows why generic code must consider what operations mean for each type.
First confirm it is a real leak and not a cache or allocator fragmentation by tracking RSS and allocator statistics. Then reproduce in staging with a heap profiler such as heaptrack or jemalloc profiling and compare snapshots to see which call stacks keep growing. LeakSanitizer catches lost blocks. Common culprits are unbounded maps, shared_ptr cycles and listeners never removed. After the fix, add a long soak test.
18
Write a C++ program that counts how often each word appears in the input.
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> freq;
std::string word;
while (std::cin >> word) {
++freq[word];
}
for (const auto& [w, c] : freq) {
std::cout << w << ' ' << c << '\n';
}
}
// Use std::unordered_map for O(1) average lookups if sorted output is not needed.
19
What does C++20 std::jthread add over std::thread?
std::jthread joins automatically in its destructor, so forgetting join no longer calls std::terminate. It also supports cooperative cancellation: the thread function can take a std::stop_token, check stop_requested() in its loop, and the owner calls request_stop(), which the destructor also does before joining. std::stop_callback lets you register cleanup actions. This makes long-running worker threads safer to write.
20
Code that erases elements from a vector inside a range-based for loop crashes. Why, and what is the correct way?
erase invalidates the iterator being used by the loop, so the next increment is undefined behaviour. Range-based for loops cannot handle this safely. Use the iterator returned by erase: for (auto it = v.begin(); it != v.end();) { if (bad(*it)) it = v.erase(it); else ++it; }. Better still, use std::erase_if, which is O(n) overall instead of O(n squared) for repeated erases.
21
You need to build an LRU cache with O(1) get and put. Which containers would you use?
Combine a doubly linked list with a hash map. std::list stores key-value pairs in usage order, with the most recent at the front. std::unordered_map maps each key to its list iterator. On get, splice the node to the front in O(1). On put, update or insert at the front and, if over capacity, remove the back node and its map entry. list iterators stay valid after splice, which makes this work.
22
A function taking a Money object is silently called with an int and gives wrong results. What is happening?
Money probably has a single-argument constructor such as Money(int paise) that is not marked explicit, so the compiler performs an implicit conversion from int. A call like pay(500) compiles even though the unit is unclear. Mark single-argument constructors explicit, so callers must write pay(Money(500)). Also consider strong types or named factory functions like Money::fromRupees to make units obvious.
23
A generic average function must accept only numeric types. How would you enforce that?
In C++20 I would constrain it: template <typename T> requires std::is_arithmetic_v<T> double average(const std::vector<T>& v). Passing a vector of strings then fails with a clear constraint error. On C++17 the same check can go in a static_assert or std::enable_if. I would also decide whether bool and char should be allowed, since they are technically arithmetic types.
Ranges let algorithms take whole containers, as in std::ranges::sort(v), instead of begin and end pairs. Views such as filter, transform, take and reverse are lazy and compose with the pipe operator, for example v | std::views::filter(isEven) | std::views::transform(square). Nothing is computed until you iterate. Ranges also use concepts, so errors are clearer, and projections let you sort by a member easily.
25
A function returns a string_view and callers sometimes print garbage. What is the likely bug?
The function probably builds or receives a temporary std::string and returns a string_view into it. When the function returns, the string is destroyed and the view dangles. Examples are returning std::string_view(a + b) or a view of a local string. Fix it by returning std::string, or make sure the view refers to data with a longer lifetime, such as a member or static storage.
Slicing happens when a derived object is copied into a base object by value. Only the base part is copied, the derived data is lost and virtual calls use the base version. Example: void draw(Shape s) called with a Circle loses Circle's radius and behaviour. Avoid it by passing polymorphic objects by reference or pointer, and consider deleting copy operations in polymorphic base classes.
unordered_map needs a hash function and equality comparison for the key type, and std::hash is not defined for user structs. Fix it by defining operator== (or defaulting it in C++20) and providing a hash functor that combines member hashes, passed as the third template argument, or by specialising std::hash for the type. std::map instead needs operator< or a comparator.
29
When do you need the typename keyword inside a template?
Inside a template, a name that depends on a template parameter, such as T::value_type, could be a type or a static member, so the compiler assumes it is a value. You must write typename T::value_type x; to say it is a type. Similarly, a dependent member template needs the template keyword, as in obj.template get<0>(). C++20 relaxes this in some contexts, but the rule still matters.
30
A full build of your C++ project takes 40 minutes. How would you reduce it?
I would measure with Clang -ftime-trace or build tooling to find the slowest files and headers. Then reduce header dependencies using forward declarations and the pimpl idiom, use Ninja for parallel builds, enable ccache or sccache, add precompiled headers for stable heavy headers, and split huge translation units. Unity builds and distributed compilation also help, and CI can cache build outputs.
Tips to crack the Google C++ interview
Practise solving DSA problems in a plain document without autocomplete, since Google interviews often use a shared editor without running code.
For data science roles, revise statistics, A/B testing and product metrics for products like YouTube, Search or Google Pay.
Prepare examples showing collaboration, handling ambiguity and doing the right thing, which the Googleyness round tends to explore.
Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
Practise the hard questions on this page aloud; Google interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the Google C++ interview?
Candidates usually go through 5 stages: Recruiter screening; Online coding assessment or phone screen; Technical interviews (coding, 3-4 rounds); Googleyness and leadership round; Hiring committee review. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.
Which topics should I prepare for the Google C++ interview?
This practice set leans on Multithreading and Concurrency (7), Standard Template Library (STL) (5), Pointers and Memory Management (4), Templates and Generic Programming (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Google interviewers ask you to walk through real work.
Are these the exact questions asked at Google?
No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Google's. They are not a leaked or verified list of past questions.
Where does Google hire C++ professionals in India?
Google has large teams in Bengaluru, Hyderabad, Gurugram, Mumbai, Pune. Openings and locations change often, so check the Google careers page and filter by city and experience.