Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About Siemens hiring for C++ roles
Siemens is a German technology company working in industrial automation, digital industries software, smart infrastructure, mobility and healthcare through Siemens Healthineers. Its India entities include engineering and technology centres in Bengaluru and Pune. It hires for software engineers, test engineers, data analysts and engineers working on industrial software and IoT.
For C++ roles, this Siemens practice set focuses most on Templates and Generic Programming (7), Modern C++ (C++11 to C++23) (6), Multithreading and Concurrency (5), Performance, Debugging and Build Tools (4). It has 3 easy, 20 medium, 7 hard questions, so you can start easy and work up to the harder ones.
Company type
Hardware & semiconductors
Headquarters
Munich, Germany
Main India offices
Mumbai, Bengaluru, Pune
Siemens C++ interview process
Online assessment (aptitude + technical)
Technical round 1
Technical round 2
Managerial round
HR round
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for SiemensStart 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
What are structured bindings and how do they work with range-based for loops?
Structured bindings, from C++17, unpack a pair, tuple, array or simple struct into named variables: auto [id, name] = getUser();. In loops they make map iteration readable: for (const auto& [key, value] : m). The variables are aliases into a hidden object, so const auto& avoids copies. They pair well with if statements with initialisers, such as if (auto [it, ok] = s.insert(x); ok).
02
Write a deadlock-free money transfer between two bank accounts.
A variadic template accepts any number of template arguments using a parameter pack, written template <typename... Args>. Before C++17 packs were processed recursively. Fold expressions from C++17 apply an operator across the whole pack in one line, for example return (args + ...); sums all arguments. They power std::make_unique, std::tuple, std::format and logging functions that take arbitrary arguments.
05
Use std::variant and std::visit to handle different message types.
std::optional<T> holds either a T or nothing, ideal for functions that may not return a value, without using magic values or pointers. std::variant<A, B> is a type-safe union that holds exactly one of the listed types, inspected with std::visit or std::get_if. std::any holds a value of any copyable type and needs any_cast to read it. Prefer optional and variant because they are checked at compile time.
Perfect forwarding passes arguments through a function template while preserving whether they were lvalues or rvalues. It uses a forwarding reference, T&& where T is deduced, together with std::forward<T>(arg). Example: template <typename... A> void make(A&&... a) { build(std::forward<A>(a)...); }. Without forward, every named parameter is an lvalue and would be copied. make_unique and emplace_back rely on it.
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.
09
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.
10
You are building a particle simulation with millions of particles. Would you store them as an array of structs or a struct of arrays?
If each update loop touches only a few fields, such as position and velocity, a struct of arrays keeps those fields contiguous, so every cache line is fully used and the compiler can vectorise with SIMD. An array of structs is simpler and better when most fields of one particle are used together. I would benchmark both, and often a hybrid that groups hot fields together works best.
11
When would you use std::set versus std::priority_queue?
priority_queue is a binary heap that gives O(1) access to the largest element and O(log n) push and pop, but you cannot search or erase arbitrary elements. std::set keeps all elements sorted with O(log n) insert, erase and find, and gives both minimum and maximum. Use priority_queue for schedulers and Dijkstra, and set or multiset when you must update or remove arbitrary items.
12
Write a C++20 concept and use it to constrain a function.
Likely causes are lock contention when all threads share one mutex, false sharing when per-thread counters sit on the same 64-byte cache line, too little work per task so thread creation dominates, or memory bandwidth limits. I would profile with perf, pad per-thread data with alignas(64) or std::hardware_destructive_interference_size, use thread-local accumulation and a thread pool, and make chunks larger.
The clean fix is to place each library's code in its own namespace so calls become liba::init and libb::init. If the source cannot change, I would check whether one function is only used internally and give it internal linkage, or wrap one library behind a shared library that hides its symbols using visibility settings. I avoid macro renaming hacks because they break silently on upgrades.
16
You need a container that holds ints, strings and doubles together. Which approach would you choose?
If the set of types is fixed and known, std::vector<std::variant<int, std::string, double>> is type-safe and needs no heap per element; std::visit handles each type. If types are open-ended, std::any works but needs any_cast and loses compile-time checks. If the items share behaviour, a base class interface with unique_ptr is cleanest. I usually prefer variant for closed sets.
17
A teammate complains that a template function produces hundreds of lines of compiler errors when misused. How do you improve this?
Constrain the template so misuse fails early with a clear message. With C++20 I would add a concept or requires clause, for example template <std::totally_ordered T>, so the error names the unmet requirement at the call site. On older standards, a static_assert with a readable message at the top of the function body helps. Good naming and a comment on expected type properties also help.
18
A low-latency system needs a queue between two threads with no locks. How would you approach it?
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.
An lvalue has identity and a persistent address, such as a named variable x. An rvalue is a temporary without lasting identity, such as 5 or the result of a + b. C++11 splits these further into lvalue, xvalue and prvalue. The distinction matters because rvalue references, written T&&, bind to temporaries and enable move semantics, letting the program steal resources instead of making expensive copies.
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.
22
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.
23
What are type traits and how does if constexpr use them?
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.
24
You are asked to modernise a large C++98 codebase to C++17. How would you plan it?
First switch the compiler standard flag and fix build errors, with CI running the full test suite. Then add clang-tidy modernize checks to convert NULL to nullptr, add override and use auto where it helps, applied module by module in small reviewed batches. Next replace raw owning pointers with unique_ptr in new and touched code. I avoid a big-bang rewrite, track progress with metrics and train the team as we go.
25
Write a GoogleTest unit test for a function, including an edge case.
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.
A dangling pointer points to memory that has already been freed or has gone out of scope, for example the address of a local variable returned from a function, or a pointer used after delete. Dereferencing it is undefined behaviour and may crash much later in unrelated code. Prevent it with smart pointers, clear ownership rules and by never returning addresses of local variables.
#include <chrono>
#include <iostream>
template <typename F>
long long timeMs(F&& f) {
auto start = std::chrono::steady_clock::now();
f();
auto end = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
// usage
// auto ms = timeMs([] { heavyWork(); });
// Use steady_clock, not system_clock, because it never jumps backwards.
29
What is the difference between a shallow copy and a deep copy?
A shallow copy copies pointer members, so two objects share one heap buffer; destroying one leaves the other dangling and causes a double free. A deep copy allocates new memory and copies the contents. The compiler-generated copy constructor copies member by member, so a class owning a raw pointer needs a custom copy constructor and copy assignment, or better, should hold a std::vector or unique_ptr instead.
30
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.
Tips to crack the Siemens C++ interview
Learn basics of industrial automation, PLCs and IoT, which connect to many Siemens software and testing roles.
Read about Siemens Xcelerator and digital twin concepts used in its industrial software.
Revise C++, Java or Python and testing fundamentals depending on the team you are applying to.
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; Siemens interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the Siemens C++ interview?
Candidates usually go through 5 stages: Online assessment (aptitude + technical); Technical round 1; Technical round 2; Managerial round; HR round. 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 Siemens C++ interview?
This practice set leans on Templates and Generic Programming (7), Modern C++ (C++11 to C++23) (6), Multithreading and Concurrency (5), Performance, Debugging and Build Tools (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Siemens interviewers ask you to walk through real work.
Are these the exact questions asked at Siemens?
No. These are curated practice questions that match the skills and difficulty usually tested in hardware & semiconductors interviews like Siemens's. They are not a leaked or verified list of past questions.
Where does Siemens hire C++ professionals in India?
Siemens has large teams in Mumbai, Bengaluru, Pune. Openings and locations change often, so check the Siemens careers page and filter by city and experience.