36 practice questions with answers for C++ interviews in Delhi.
C++ jobs in Delhi
Delhi NCR has one of India's biggest pools of IT, consulting, banking and start-up jobs. Delhi itself hosts many corporate, government-tech and consulting offices, and most candidates also apply across Noida and Gurgaon, so interviews here mix service-company and product-company styles.
Below are 36 questions that match the mix of service, product and domain employers hiring junior c++ developers in Delhi.
Solved for DelhiStart 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
Use a C++20 ranges pipeline to get squares of the first three even numbers.
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
auto result = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; })
| std::views::take(3);
for (int x : result) std::cout << x << ' '; // 4 16 36
}
// Views are lazy: elements are processed only while iterating.
02
A function returns a reference to a local variable and the code sometimes works. Explain what is happening.
The local is destroyed when the function returns, so the reference dangles and using it is undefined behaviour. It may seem to work because the old bytes remain on the stack until another call overwrites them. Compilers warn with -Wreturn-local-addr or -Wreturn-stack-address. The fix is to return by value; copy elision and move semantics make returning objects cheap.
03
What is the difference between an inline function and a macro?
A macro is text substitution done by the preprocessor with no type checking, so #define SQ(x) x*x gives a wrong result for SQ(a+1) and may evaluate arguments twice. An inline function is a real function with type checking, scope and debugger support, and the compiler may expand it at the call site. In modern C++ inline mainly allows a function to be defined in a header without breaking the One Definition Rule.
04
Explain the rule of three, rule of five and rule of zero.
Rule of three: if a class needs a custom destructor, copy constructor or copy assignment, it usually needs all three because it manages a resource. Rule of five adds the move constructor and move assignment from C++11. Rule of zero says the best design avoids writing any of them by holding resources in members such as std::vector, std::string and unique_ptr, which already manage themselves.
05
What is template argument deduction and class template argument deduction?
For function templates the compiler deduces T from the call, so maxOf(3, 7) deduces int; mixing int and double fails because T would be ambiguous. Class template argument deduction, added in C++17, lets you write std::vector v{1, 2, 3}; or std::pair p(1, 2.5); without spelling the template arguments. Deduction guides can be written to tell the compiler how to deduce types from constructors.
06
Why are templates usually defined in header files?
A template is only a pattern; code is generated when it is instantiated with concrete types, and the compiler must see the full definition at that point. If the body lives in a .cpp file, other translation units cannot instantiate it and you get linker errors. The usual fix is defining templates in headers, or using explicit instantiation in the .cpp for a known, fixed set of types.
Concepts are named compile-time predicates on template parameters. You can write template <std::integral T> T gcd(T a, T b) or define your own with a requires expression. If a type does not satisfy the concept, the compiler reports a short, readable error at the call site instead of pages of instantiation errors. Concepts also allow overloading by constraint and document the template's expectations.
08
List the gdb commands you would use to debug a crash.
g++ -g -O0 main.cpp -o app # build with debug symbols
gdb ./app # or: gdb ./app core
(gdb) run arg1 arg2 # start the program
(gdb) bt # backtrace after the crash
(gdb) frame 2 # select a stack frame
(gdb) info locals # show local variables
(gdb) print ptr->size # inspect an expression
(gdb) break order.cpp:42 # set a breakpoint
(gdb) watch total # stop when a variable changes
(gdb) next / step / continue # step over, step into, resume
09
How does std::condition_variable work and what are spurious wakeups?
A condition variable lets a thread sleep until another thread signals that some state changed. The waiter holds a unique_lock and calls cv.wait(lock, predicate), which releases the mutex while sleeping and reacquires it on wake. The notifier changes the state under the mutex and calls notify_one or notify_all. Threads can wake without notification, called spurious wakeups, so always wait with a predicate that rechecks the condition.
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.
11
Implement a generic Stack class template backed by std::vector.
For one producer and one consumer, a single-producer single-consumer ring buffer is the standard answer: a fixed-size array with atomic head and tail indices, using release on publish and acquire on read, and padding so the indices sit on different cache lines. It avoids allocation and syscalls. For multiple producers I would use a proven library rather than writing my own, and verify with stress tests and TSan.
13
Write a move constructor and move assignment operator for a class that owns a buffer.
There are four stages. The preprocessor expands #include directives and macros into a translation unit. The compiler turns each translation unit into assembly and then an object file. The linker combines object files and libraries and resolves symbols into an executable. At run time the loader maps it into memory. A missing function body therefore shows up as a linker error, not a compiler error.
15
Sorting a vector of large objects is slow. What can you do?
Sorting moves elements many times, so large objects that copy instead of move are expensive. First ensure the type has a noexcept move constructor. If moves are still heavy, sort a vector of indices or pointers with a comparator on the key, then reorder once if needed. Precomputing the sort key avoids repeated expensive comparisons. Use std::stable_sort only when equal-element order matters.
16
What is the erase-remove idiom and what replaced it in C++20?
std::remove does not delete elements; it shifts the kept elements forward and returns an iterator to the new logical end. You then call erase to shrink the container: v.erase(std::remove(v.begin(), v.end(), 0), v.end());. remove_if works the same with a predicate. C++20 adds std::erase(v, value) and std::erase_if(v, pred), which do both steps in one call.
17
Write a program where two threads print odd and even numbers alternately up to 10.
Situation: a customer-facing crash was reported two days before a feature demo. Task: handle both without dropping quality. Action: I informed my lead immediately, estimated both tasks, and we agreed the crash came first because it affected users. I fixed and released it in half a day, then cut one optional part of the feature after agreeing with the product owner. Result: the crash was resolved and the demo went ahead on time.
19
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.
20
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.
21
Why should you prefer make_unique and make_shared over calling new directly?
They avoid writing raw new, so no allocated object can leak if another expression in the same call throws. make_shared also allocates the object and the control block together in one allocation, which is faster and more cache friendly. One trade-off: with make_shared the memory block stays allocated until every weak_ptr is gone, which matters for very large objects.
22
Tell me about a time you designed the class structure for a module and how you handled review feedback.
Situation: I had to build a report export module supporting PDF, CSV and Excel. Task: design it so new formats were easy to add. Action: I proposed an abstract Exporter interface and a factory, shared a short design note and asked seniors to review before coding. They pointed out duplicated formatting logic, so I extracted a Formatter helper. Result: a fourth format was later added in one day with no changes to existing classes.
23
Code that takes bool& from a std::vector<bool> fails to compile. Why?
std::vector<bool> is a special case that packs bits, so elements are not real bool objects and operator[] returns a proxy object, not bool&. You cannot take a reference or pointer to a single element, and it is not thread-safe to write neighbouring elements from different threads. If you need real bools use std::vector<char>, std::deque<bool>, or std::bitset when the size is fixed.
24
What is function overloading and how does the compiler choose an overload?
Overloading means several functions share a name but differ in the number or types of parameters; return type alone is not enough. The compiler runs overload resolution: exact matches win, then promotions such as char to int, then standard conversions, then user-defined conversions. If two candidates are equally good the call is ambiguous and compilation fails. Name mangling gives every overload a unique linker symbol.
Resource Acquisition Is Initialization ties a resource's lifetime to an object's lifetime. The constructor acquires the resource, such as memory, a file, a socket or a mutex, and the destructor releases it. Because destructors run automatically when a scope ends, even when an exception is thrown, resources are never leaked. std::unique_ptr, std::lock_guard and std::fstream are standard RAII types.
26
Find the middle node of a linked list in a single pass.
Node* middle(Node* head) {
Node* slow = head;
Node* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// fast moves two steps and slow one step, so slow stops at the middle.
Any insertion that causes reallocation, when size exceeds capacity, invalidates all iterators, pointers and references. Insertion without reallocation invalidates those at or after the insertion point. erase invalidates iterators at and after the erased element. clear and resize to a larger size beyond capacity invalidate everything. Holding a pointer to an element and then calling push_back is a classic bug.
Most compilers give each polymorphic class a vtable, a static table of function pointers for its virtual functions. Every object stores a hidden vptr pointing to its class's vtable. A call through a base pointer loads the vptr, looks up the slot and jumps to the right override. The cost is one pointer per object, an indirect call and usually no inlining, which matters only in very hot loops.
29
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.
30
Describe a time you improved code quality by changing how memory was managed.
Situation: our module used raw new and delete everywhere and QA reported frequent leaks. Task: make it safe without a full rewrite. Action: I proposed a step-by-step migration to unique_ptr and std::vector, wrote a one-page ownership guideline and enabled LeakSanitizer in CI so new leaks failed the build. Result: leak reports dropped to zero within two sprints and reviews became faster because ownership was obvious.
Templates give static polymorphism: resolved at compile time, inlinable and fast, but types must be known at compile time and code size grows. Virtual functions give dynamic polymorphism: one compiled body, types can be chosen at run time, plugins are possible, at the cost of an indirect call. I use templates for performance-critical generic algorithms and virtual interfaces for runtime-configurable components.
33
Compute the sum of a large vector in parallel using std::async.
#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)
34
Write a C++20 concept and use it to constrain a function.
Type traits in <type_traits> answer questions about types at compile time, such as std::is_integral_v<T>, std::is_pointer_v<T> or std::is_same_v<T, U>, and transform types, such as std::remove_reference_t. if constexpr picks a branch at compile time and discards the other, so code like if constexpr (std::is_integral_v<T>) can call integer-only operations safely inside a generic function.
36
A C++ server crashes with a segmentation fault in production. How do you debug it?
Make sure core dumps are enabled with ulimit -c unlimited or systemd-coredump, and keep debug symbols for release builds. Load the core with gdb binary core, run bt to see the stack trace, then inspect frames and variables. If the stack looks corrupted, reproduce in staging with AddressSanitizer. I would also check logs around the crash time and recent deployments, then add a regression test with the fix.
Companies with large offices in Delhi include Samsung. Use their company pages below to practise employer-specific sets.
Are C++ interviews in Delhi different from other cities?
The questions depend more on the company than the city. Delhi's mix of employers decides the style: Delhi itself hosts many corporate, government-tech and consulting offices, and most candidates also apply across Noida and Gurgaon, so interviews here mix service-company and product-company styles
How do I find C++ jobs in Delhi?
Shortlist companies with Delhi offices, keep your CV focused on C++ projects, apply on company career pages and job portals with the Delhi filter, and practise the questions on this page before each interview.