here are 25 advanced-level C++ interview questions with corresponding answers, tailored for an IT department in an insurance company dealing with life insurance, property insurance, health insurance, and claims processing:
1. What are smart pointers in C++ and how do they help with memory management?
Answer: Smart pointers are objects that ensure proper memory management by automatically releasing dynamically allocated memory when the smart pointer goes out of scope. The most commonly used smart pointers are `std::unique_ptr`, `std::shared_ptr`, and `std::weak_ptr`. They help prevent memory leaks and dangling pointers.
2. Explain the RAII (Resource Acquisition Is Initialization) idiom in C++.
Answer: RAII is a programming idiom used to manage resources such as memory, file handles, and network connections. The idea is to bind the resource's lifecycle to the lifetime of an object, ensuring that the resource is properly released when the object goes out of scope. This is often implemented using smart pointers and destructors.
3. How does C++11 improve the handling of multithreading?
Answer: C++11 introduces a standardized memory model and a set of multithreading libraries, including `std::thread`, `std::mutex`, `std::unique_lock`, `std::condition_variable`, and `std::atomic`. These additions make it easier to write portable and efficient multithreaded code.
4. What is the difference between `std::map` and `std::unordered_map` in C++?
Answer: `std::map` is an ordered associative container that stores key-value pairs in a balanced binary tree, allowing for ordered traversal and logarithmic time complexity for insertions, deletions, and lookups. `std::unordered_map` is an unordered associative container that uses a hash table for storage, providing average constant time complexity for insertions, deletions, and lookups, but without any guarantees on order.
5. Explain the concept of SFINAE (Substitution Failure Is Not An Error) in C++.
Answer: SFINAE is a C++ template metaprogramming feature that allows the compiler to choose the best match for a template function or class by discarding candidates that result in substitution failures during template instantiation. It enables conditional compilation and the creation of more flexible and generic code.
6. How do you handle exceptions in C++? Give an example.
Answer: Exceptions in C++ are handled using `try`, `catch`, and `throw` keywords. A `try` block contains code that might throw an exception, `catch` blocks handle specific exceptions, and `throw` is used to signal an exception. Example:
```cpp
try {
// Code that may throw an exception
throw std::runtime_error("An error occurred");
} catch (const std::runtime_error& e) {
std::cout << "Caught runtime error: " << e.what() << std::endl;
} catch (...) {
std::cout << "Caught an unknown exception" << std::endl;
}
```
7. What is the difference between `new` and `malloc` in C++?
Answer: `new` allocates memory and calls the constructor to initialize the object, while `malloc` only allocates memory without calling any constructors. `new` returns a properly typed pointer, whereas `malloc` returns a `void*` that must be cast to the appropriate type. Additionally, memory allocated with `new` must be freed with `delete`, while memory allocated with `malloc` must be freed with `free`.
8. Explain the use of `decltype` in C++11 with an example.
Answer: `decltype` is used to query the type of an expression at compile time. It is useful for template metaprogramming and writing generic code. Example:
```cpp
int x = 5;
decltype(x) y = 10; // y has the same type as x, which is int
```
9. How do you implement a thread-safe singleton in C++11?
Answer: A thread-safe singleton can be implemented using a local static variable inside a function:
```cpp
class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance; // Guaranteed to be thread-safe
return instance;
}
private:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
```
10. What is the purpose of `constexpr` in C++11?
Answer: `constexpr` is used to declare that the value of a variable or the return value of a function can be evaluated at compile time. This enables optimizations and ensures that certain computations are performed at compile time rather than runtime.
11. How do you use `std::variant` in C++17?
Answer: `std::variant` is a type-safe union that can hold a value of one of several specified types. Example:
```cpp
#include
#include
std::variant v;
v = 42;
std::cout << std::get(v) << std::endl;
v = 3.14;
std::cout << std::get(v) << std::endl;
v = "hello";
std::cout << std::get(v) << std::endl;
```
12. What are lambda expressions in C++ and how are they used?
Answer: Lambda expressions are anonymous functions that can be defined in-place. They are used for short snippets of code, often for passing to algorithms or as event handlers. Example:
```cpp
auto add = [](int a, int b) { return a + b; };
std::cout << add(2, 3) << std::endl; // Output: 5
```
13. Explain move semantics and rvalue references in C++11.
Answer: Move semantics and rvalue references enable the efficient transfer of resources from temporary objects (rvalues) to new objects, avoiding unnecessary copying. This is achieved using the `&&` syntax for rvalue references and `std::move` to cast to an rvalue reference. Example:
```cpp
std::vector v1 = {1, 2, 3};
std::vector v2 = std::move(v1); // v2 now owns the data, v1 is left in a valid but unspecified state
```
14. How does the `override` keyword work in C++11?
Answer: The `override` keyword is used in a derived class to indicate that a member function is intended to override a base class virtual function. This helps catch errors at compile time if the function signatures do not match. Example:
```cpp
class Base {
public:
virtual void foo() {}
};
class Derived : public Base {
public:
void foo() override { // Correctly overrides Base::foo
// Function implementation
}
};
```
15. What is the purpose of the `final` keyword in C++11?
Answer: The `final` keyword is used to prevent a class from being inherited or a virtual function from being overridden in derived classes. This can be useful for optimization and design clarity. Example:
```cpp
class Base final {
// Class implementation
};
class Derived : public Base { // Error: cannot inherit from final class
// Class implementation
};
```
16. Explain the concept of type traits in C++ and give an example.
Answer: Type traits are templates that provide information about types at compile time. They are part of the `` header and are used for type introspection and metaprogramming. Example:
```cpp
#include
#include
template
void printTypeInfo() {
if (std::is_integral::value) {
std::cout << "Integral type" << std::endl;
} else {
std::cout << "Non-integral type" << std::endl;
}
}
printTypeInfo(); // Output: Integral type
printTypeInfo(); // Output: Non-integral type
```
17. What are the benefits of using `std::shared_ptr` and `std::weak_ptr`?
Answer: `std::shared_ptr` is a smart pointer that maintains a reference count, ensuring that the resource it manages is only deleted when all `std::shared_ptr`s referencing it are destroyed. `std::weak_ptr` is used to break circular references by providing a non-owning reference to the resource managed by `std::shared_ptr`.
18. How do you implement polymorphism in C++?
Answer: Polymorphism in C++ is implemented using base class pointers or references to derived class objects and virtual functions. Example:
```cpp
class Base {
public:
virtual void show() { std::cout << "Base show" << std::endl; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived show" << std::endl; }
};
Base* b = new Derived();
b->show(); // Output: Derived show
delete b;
```
19. What is the significance of the `noexcept` specifier in C++11?
Answer: The `noexcept` specifier indicates that a function does not throw any exceptions. This allows the compiler to make optimizations and can be used to enforce exception safety. Example:
```cpp
void foo() noexcept {
// Function implementation
}
```
20. Explain the use of `std::lock_guard` and `std::unique_lock` in C++.
Answer: `std::lock_guard` and `std::unique_lock` are RAII wrappers for managing mutex locks. `std::lock_guard` is a simple, non-owning wrapper that locks a mutex on creation and unlocks it on destruction. `std::unique_lock
` is more flexible, allowing for deferred locking, unlocking, and ownership transfer. Example:
```cpp
std::mutex mtx;
void threadSafeFunction() {
std::lock_guard guard(mtx);
// Critical section
}
```
21. How do you create and manage a thread pool in C++?
Answer: A thread pool in C++ can be created using `std::thread`, `std::queue`, `std::condition_variable`, and a vector of threads. Tasks are pushed to the queue, and worker threads pull and execute tasks. Example:
```cpp
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
void enqueueTask(std::function task);
private:
std::vector workers;
std::queue> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop;
void workerThread();
};
```
22. What are `std::promise` and `std::future` in C++?
Answer: `std::promise` and `std::future` are synchronization primitives used for asynchronous programming. `std::promise` is used to set a value or exception, and `std::future` is used to retrieve the result. They allow for safe communication between threads. Example:
```cpp
std::promise promise;
std::future future = promise.get_future();
std::thread t([](std::promise p) {
p.set_value(42);
}, std::move(promise));
std::cout << future.get() << std::endl; // Output: 42
t.join();
```
23. How do you handle large files efficiently in C++?
Answer: Large files can be handled efficiently in C++ by using memory-mapped files, which map a file's contents into memory for fast access. This can be done using platform-specific APIs like `mmap` on Unix or `CreateFileMapping` on Windows. Example:
```cpp
#include
#include
#include
int fd = open("largefile.txt", O_RDONLY);
struct stat sb;
fstat(fd, &sb);
char* addr = static_cast(mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
if (addr == MAP_FAILED) {
close(fd);
throw std::runtime_error("mmap failed");
}
// Process file contents
munmap(addr, sb.st_size);
close(fd);
```
24. What is the difference between shallow copy and deep copy in C++?
Answer: A shallow copy duplicates the object's memory address, copying the pointer to the same memory location, while a deep copy creates a new object and duplicates the values from the original object, ensuring that both objects are independent. Example:
```cpp
class ShallowCopy {
public:
int* data;
ShallowCopy(int value) {
data = new int(value);
}
ShallowCopy(const ShallowCopy& other) {
data = other.data;
}
~ShallowCopy() {
delete data;
}
};
class DeepCopy {
public:
int* data;
DeepCopy(int value) {
data = new int(value);
}
DeepCopy(const DeepCopy& other) {
data = new int(*other.data);
}
~DeepCopy() {
delete data;
}
};
```
25. Explain the concept of the rule of five in C++11.
Answer: The rule of five in C++11 states that if a class requires a user-defined destructor, copy constructor, copy assignment operator, move constructor, or move assignment operator, it likely needs all five. This ensures proper resource management and avoids undefined behavior. Example:
```cpp
class Resource {
public:
Resource() = default;
~Resource() { delete resource; }
Resource(const Resource& other) {
resource = new int(*other.resource);
}
Resource& operator=(const Resource& other) {
if (this != &other) {
delete resource;
resource = new int(*other.resource);
}
return *this;
}
Resource(Resource&& other) noexcept : resource(other.resource) {
other.resource = nullptr;
}
Resource& operator=(Resource&& other) noexcept {
if (this != &other) {
delete resource;
resource = other.resource;
other.resource = nullptr;
}
return *this;
}
private:
int* resource = nullptr;
};
```