Skip to content

Oracle C++ Interview Questions & Answers

Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.

About Oracle hiring for C++ roles

Oracle develops database software, cloud infrastructure (OCI), enterprise applications such as Fusion ERP and NetSuite, and industry software for banking and healthcare. India hosts major Oracle development and support centres, including Oracle Financial Services Software. It hires for software developers, QA engineers, database engineers, cloud support and data analytics roles.

For C++ roles, this Oracle practice set focuses most on Modern C++ (C++11 to C++23) (5), Standard Template Library (STL) (5), Performance, Debugging and Build Tools (4), Pointers and Memory Management (4). It has 2 easy, 16 medium, 12 hard questions, so you can start easy and work up to the harder ones.

Company type
Product
Headquarters
Austin, Texas, USA
Main India offices
Bengaluru, Hyderabad, Noida, Mumbai, Pune

Oracle C++ interview process

  1. Online assessment (aptitude + coding + CS MCQs)
  2. Technical round 1
  3. Technical round 2
  4. Managerial round
  5. HR round

Typical pattern based on public candidate experiences. Rounds vary by role, team and year.

Solved for OracleStart 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 GoogleTest unit test for a function, including an edge case.

Save to ▾
Show answer
#include <gtest/gtest.h> #include <stdexcept> #include <vector> double average(const std::vector<int>& v) { if (v.empty()) throw std::invalid_argument("empty"); long long s = 0; for (int x : v) s += x; return static_cast<double>(s) / v.size(); } TEST(AverageTest, ComputesMean) { EXPECT_DOUBLE_EQ(average({2, 4, 6}), 4.0); } TEST(AverageTest, ThrowsOnEmpty) { EXPECT_THROW(average({}), std::invalid_argument); }
02

What is a void pointer and when would you use it?

Save to ▾
Show answer
A void* can hold the address of any object type but cannot be dereferenced or used in arithmetic until it is cast back to a real type. It appears in C APIs such as malloc, memcpy and callback user-data parameters. In C++ code, templates, std::any or std::variant are better because void* removes type safety and mistakes appear only at run time.
03

Your application is slow and you are asked to optimise it. Where do you start?

Save to ▾
Show answer
I start by measuring, not guessing. I define a target, such as p99 under 50 ms, create a repeatable benchmark, and profile with perf to find where time actually goes. Then I fix the biggest hotspot first, usually algorithmic complexity, unnecessary copies, allocations or I/O, and re-measure after each change. I keep correctness tests running and stop when the target is met.
04

List the gdb commands you would use to debug a crash.

Save to ▾
Show answer
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
05

Describe a time you improved code quality by changing how memory was managed.

Save to ▾
Show answer
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.
06

Implement a basic Observer pattern for an event publisher.

Save to ▾
Show answer
#include <functional> #include <string> #include <vector> class EventBus { public: using Handler = std::function<void(const std::string&)>; int subscribe(Handler h) { handlers_.push_back({nextId_, std::move(h)}); return nextId_++; } void unsubscribe(int id) { std::erase_if(handlers_, [id](const auto& p) { return p.first == id; }); } void publish(const std::string& msg) const { for (const auto& [id, h] : handlers_) h(msg); } private: std::vector<std::pair<int, Handler>> handlers_; int nextId_ = 0; };
07

How would you choose between exceptions, error codes and std::expected for error handling?

Save to ▾
Show answer
Exceptions suit rare, truly exceptional failures, keep the happy path clean and work well with RAII, but have unpredictable cost when thrown and are often disabled in embedded or game code. Error codes are explicit and cheap but easy to ignore. C++23 std::expected<T, E> returns either a value or an error, combining explicit handling with clean types. I follow the project convention and use expected for expected failures like parsing.
08

A function taking a Money object is silently called with an int and gives wrong results. What is happening?

Save to ▾
Show answer
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.
09

Many threads read a shared configuration object constantly, but it changes only once an hour. How do you synchronise it efficiently?

Save to ▾
Show answer
A plain mutex would serialise all readers. Option one is std::shared_mutex: readers take shared_lock and run in parallel, the updater takes unique_lock. Option two, often faster, is to keep the config in a std::shared_ptr<const Config> and swap in a new immutable object atomically with std::atomic<std::shared_ptr> in C++20; readers grab a copy of the pointer and never block the writer.
10

A program does millions of lookups in a std::map with string keys and is slow. How would you speed it up?

Save to ▾
Show answer
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.
11

What is a custom deleter for a smart pointer and when do you need one?

Save to ▾
Show answer
A custom deleter tells the smart pointer how to release a resource that was not created with plain new. For example std::unique_ptr<FILE, decltype(&fclose)> f(fopen(path, mode), &fclose); closes the file automatically. Deleters are used for C library handles, sockets, OS handles and objects from custom pools. For unique_ptr the deleter is part of the type, while shared_ptr stores it in the control block.
12

What is the difference between push_back and emplace_back?

Save to ▾
Show answer
push_back takes an existing object, copying or moving it into the container. emplace_back forwards constructor arguments and builds the element directly in place, which can avoid a temporary. For example v.emplace_back(name, age) constructs a Person inside the vector. The gain is small when you already have an object, and emplace_back can call explicit constructors unexpectedly, so use it deliberately.
13

Implement a simple fixed-size thread pool.

Save to ▾
Show answer
#include <condition_variable> #include <functional> #include <mutex> #include <queue> #include <thread> #include <vector> class ThreadPool { std::vector<std::thread> workers_; std::queue<std::function<void()>> tasks_; std::mutex m_; std::condition_variable cv_; bool stop_ = false; public: explicit ThreadPool(std::size_t n) { for (std::size_t i = 0; i < n; ++i) workers_.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lk(m_); cv_.wait(lk, [this] { return stop_ || !tasks_.empty(); }); if (stop_ && tasks_.empty()) return; task = std::move(tasks_.front()); tasks_.pop(); } task(); } }); } void submit(std::function<void()> f) { { std::lock_guard<std::mutex> lk(m_); tasks_.push(std::move(f)); } cv_.notify_one(); } ~ThreadPool() { { std::lock_guard<std::mutex> lk(m_); stop_ = true; } cv_.notify_all(); for (auto& w : workers_) w.join(); } };
14

Tell me about a performance improvement you delivered and how you measured it.

Save to ▾
Show answer
Situation: our risk calculation batch took 90 minutes and blocked morning reports. Task: bring it under 30 minutes. Action: I profiled with perf and found most time in allocating small objects and a map lookup inside the inner loop. I preallocated buffers, replaced the map with a flat sorted vector and parallelised independent portfolios with a thread pool, validating outputs against the old version. Result: 22 minutes, with identical numbers.
15

You inherit a 3000-line class that handles parsing, validation, database and logging. How would you refactor it?

Save to ▾
Show answer
It breaks the single responsibility principle. First I add characterisation tests around current behaviour. Then I extract cohesive pieces into separate classes such as Parser, Validator and Repository, injected through interfaces so they can be mocked. I move step by step, keeping the old public API as a facade, and merge small refactors frequently instead of one big rewrite, so risk stays low and reviews stay easy.
16

Implement a minimal unique_ptr-like class.

Save to ▾
Show answer
template <typename T> class UniquePtr { T* ptr_ = nullptr; public: explicit UniquePtr(T* p = nullptr) : ptr_(p) {} ~UniquePtr() { delete ptr_; } UniquePtr(const UniquePtr&) = delete; UniquePtr& operator=(const UniquePtr&) = delete; UniquePtr(UniquePtr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; } UniquePtr& operator=(UniquePtr&& o) noexcept { if (this != &o) { delete ptr_; ptr_ = o.ptr_; o.ptr_ = nullptr; } return *this; } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } };
17

Use std::variant and std::visit to handle different message types.

Save to ▾
Show answer
#include <iostream> #include <string> #include <variant> struct Login { std::string user; }; struct Logout { int sessionId; }; using Message = std::variant<Login, Logout>; template <class... Ts> struct Overloaded : Ts... { using Ts::operator()...; }; void handle(const Message& m) { std::visit(Overloaded{ [](const Login& l) { std::cout << "login " << l.user << '\n'; }, [](const Logout& o) { std::cout << "logout " << o.sessionId << '\n'; }}, m); } // Adding a new type without a handler becomes a compile error.
18

Implement an LRU cache with get and put in O(1).

Save to ▾
Show answer
#include <list> #include <unordered_map> class LRUCache { int cap_; std::list<std::pair<int, int>> items_; // front = most recent std::unordered_map<int, std::list<std::pair<int, int>>::iterator> pos_; public: explicit LRUCache(int capacity) : cap_(capacity) {} int get(int key) { auto it = pos_.find(key); if (it == pos_.end()) return -1; items_.splice(items_.begin(), items_, it->second); return it->second->second; } void put(int key, int value) { if (auto it = pos_.find(key); it != pos_.end()) { it->second->second = value; items_.splice(items_.begin(), items_, it->second); return; } if (static_cast<int>(items_.size()) == cap_) { pos_.erase(items_.back().first); items_.pop_back(); } items_.emplace_front(key, value); pos_[key] = items_.begin(); } };
19

Your program gives correct output in a debug build but wrong output in a release build. How do you investigate?

Save to ▾
Show answer
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.
20

A function returns a string_view and callers sometimes print garbage. What is the likely bug?

Save to ▾
Show answer
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.
21

Implement a simple String class that follows the rule of five.

Save to ▾
Show answer
#include <cstring> #include <utility> class String { char* data_ = nullptr; std::size_t len_ = 0; public: String(const char* s = "") : len_(std::strlen(s)) { data_ = new char[len_ + 1]; std::memcpy(data_, s, len_ + 1); } ~String() { delete[] data_; } String(const String& o) : String(o.data_) {} String(String&& o) noexcept : data_(std::exchange(o.data_, nullptr)), len_(std::exchange(o.len_, 0)) {} String& operator=(String o) noexcept { // copy-and-swap handles both std::swap(data_, o.data_); std::swap(len_, o.len_); return *this; } const char* c_str() const { return data_ ? data_ : ""; } };
22

When are std::vector iterators invalidated?

Save to ▾
Show answer
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.
23

Using a custom struct as the key of an unordered_map gives a compile error. Why, and how do you fix it?

Save to ▾
Show answer
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.
24

Write a lookup function that uses std::optional instead of returning -1 or a null pointer.

Save to ▾
Show answer
#include <optional> #include <string> #include <unordered_map> std::optional<int> findAge(const std::unordered_map<std::string, int>& db, const std::string& name) { if (auto it = db.find(name); it != db.end()) return it->second; return std::nullopt; } // caller if (auto age = findAge(db, "Meera")) { use(*age); } int a = findAge(db, "Unknown").value_or(0);
25

A service occasionally freezes and thread dumps show two threads each waiting on a mutex held by the other. How do you fix it?

Save to ▾
Show answer
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.
26

Tell me about a time you convinced your team to adopt a new C++ feature or practice.

Save to ▾
Show answer
Situation: our team avoided smart pointers, and leaks kept reaching QA. Task: get agreement to adopt unique_ptr in new code. Action: I prepared a short benchmark showing no measurable overhead, converted one leaky module as a pilot, and presented before and after defect counts at our tech sync. I also wrote clang-tidy rules to help. Result: the team agreed to make it a coding standard and leak bugs dropped sharply in the next quarter.
27

What are variadic templates and fold expressions?

Save to ▾
Show answer
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.
28

A generic average function must accept only numeric types. How would you enforce that?

Save to ▾
Show answer
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.
29

What are C++20 concepts?

Save to ▾
Show answer
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.
30

Implement your own is_pointer type trait.

Save to ▾
Show answer
template <typename T> struct IsPointer { static constexpr bool value = false; }; template <typename T> struct IsPointer<T*> { // partial specialization for pointers static constexpr bool value = true; }; template <typename T> inline constexpr bool IsPointer_v = IsPointer<T>::value; static_assert(IsPointer_v<int*>); static_assert(!IsPointer_v<int>); // The real std::is_pointer also strips const and volatile first.

Tips to crack the Oracle C++ interview

  • Revise SQL and PL/SQL deeply, including joins, indexes, transactions and query optimisation, as databases are central to Oracle.
  • Read basic OCI concepts like compute, storage and autonomous database if you are interviewing for cloud teams.
  • Practise explaining DBMS, operating systems and networking fundamentals, which are often tested in Oracle technical rounds.
  • 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; Oracle interviewers usually ask follow-ups on your first answer.

Frequently asked questions

How many rounds are there in the Oracle C++ interview?

Candidates usually go through 5 stages: Online assessment (aptitude + coding + CS MCQs); 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 Oracle C++ interview?

This practice set leans on Modern C++ (C++11 to C++23) (5), Standard Template Library (STL) (5), Performance, Debugging and Build Tools (4), Pointers and Memory Management (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Oracle interviewers ask you to walk through real work.

Are these the exact questions asked at Oracle?

No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Oracle's. They are not a leaked or verified list of past questions.

Where does Oracle hire C++ professionals in India?

Oracle has large teams in Bengaluru, Hyderabad, Noida, Mumbai, Pune. Openings and locations change often, so check the Oracle careers page and filter by city and experience.

C++ questions for similar companies