C++ Memory Management Deep Dive Quiz
40 in-depth questions covering advanced C++ memory management with custom allocators, memory pools, RAII patterns, and cache-friendly programming — with 16 code examples to solidify understanding.
Question 1
What is the std::allocator interface in C++?
template <typename T>
class MyAllocator {
public:
using value_type = T;
T* allocate(std::size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, std::size_t n) {
::operator delete(p);
}
// Other required methods...
};Question 2
What is RAII (Resource Acquisition Is Initialization)?
class FileHandle {
FILE* file;
public:
FileHandle(const char* filename) : file(fopen(filename, "r")) {
if (!file) throw std::runtime_error("Failed to open file");
}
~FileHandle() { if (file) fclose(file); }
FILE* get() { return file; }
// Prevent copying
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
};Question 3
What is a memory pool allocator?
class MemoryPool {
struct Block {
Block* next;
};
Block* free_list = nullptr;
char* pool;
size_t block_size;
public:
MemoryPool(size_t pool_size, size_t blk_size)
: block_size(blk_size), pool(new char[pool_size]) {
// Initialize free list
for (size_t i = 0; i < pool_size; i += blk_size) {
Block* block = reinterpret_cast<Block*>(&pool[i]);
block->next = free_list;
free_list = block;
}
}
void* allocate() {
if (!free_list) return nullptr;
Block* block = free_list;
free_list = block->next;
return block;
}
void deallocate(void* ptr) {
Block* block = static_cast<Block*>(ptr);
block->next = free_list;
free_list = block;
}
};Question 4
What is cache alignment and why is it important?
struct alignas(64) CacheAlignedData {
int data;
// Padding ensures struct doesn't share cache lines
};
// Without alignment:
struct UnalignedData {
char c;
int data; // May share cache line with adjacent objects
};Question 5
What is the difference between internal and external memory fragmentation?
Question 6
What is a custom deleter in smart pointers?
auto file_deleter = [](FILE* f) { if (f) fclose(f); };
std::unique_ptr<FILE, decltype(file_deleter)> file(
fopen("data.txt", "r"), file_deleter);
// Or with custom class
auto cuda_deleter = [](float* ptr) { cudaFree(ptr); };
std::unique_ptr<float, decltype(cuda_deleter)> gpu_mem(nullptr, cuda_deleter);Question 7
What is an arena allocator?
class ArenaAllocator {
char* buffer;
size_t capacity;
size_t offset = 0;
public:
ArenaAllocator(size_t cap) : capacity(cap), buffer(new char[cap]) {}
void* allocate(size_t size) {
if (offset + size > capacity) return nullptr;
void* ptr = &buffer[offset];
offset += size;
return ptr;
}
// No individual deallocation - all freed at once
void reset() { offset = 0; }
~ArenaAllocator() { delete[] buffer; }
};Question 8
What is the rule of three/five/zero in C++?
// Rule of Zero: Use smart pointers/default operations
class RuleOfZero {
std::unique_ptr<int> data;
// Compiler generates correct copy/move operations
};
// Rule of Three: Manual copy constructor, assignment, destructor
class RuleOfThree {
int* data;
public:
RuleOfThree() : data(new int[100]) {}
~RuleOfThree() { delete[] data; }
RuleOfThree(const RuleOfThree& other) : data(new int[100]) {
std::copy(other.data, other.data + 100, data);
}
RuleOfThree& operator=(const RuleOfThree& other) {
if (this != &other) {
delete[] data;
data = new int[100];
std::copy(other.data, other.data + 100, data);
}
return *this;
}
};Question 9
What is false sharing in multi-threaded applications?
struct BadLayout {
std::atomic<int> counter1; // Cache line 1
std::atomic<int> counter2; // Still cache line 1 - false sharing!
};
struct GoodLayout {
std::atomic<int> counter1; // Cache line 1
char padding[60]; // Fill cache line
std::atomic<int> counter2; // Cache line 2 - no false sharing
};Question 10
What is a placement new operator?
char buffer[sizeof(MyClass)];
// Construct object in existing memory
MyClass* obj = new (buffer) MyClass(args);
// Use object...
obj->~MyClass(); // Manual destruction
// Buffer can be reused or freed
// No delete - memory wasn't allocated by newQuestion 11
What is memory ownership and transfer of ownership?
class DataOwner {
std::unique_ptr<int[]> data;
public:
DataOwner(size_t size) : data(new int[size]) {}
// Transfer ownership
std::unique_ptr<int[]> release() {
return std::move(data);
}
// Share ownership
std::shared_ptr<int[]> share() {
return data; // Increases ref count
}
};Question 12
What is cache-friendly data structure design?
// Cache-friendly: Structure of Arrays (SoA)
struct ParticlesSoA {
std::vector<float> x, y, z; // Contiguous memory
std::vector<float> vx, vy, vz;
};
// Cache-unfriendly: Array of Structures (AoS)
struct Particle {
float x, y, z, vx, vy, vz;
};
std::vector<Particle> particlesAoS; // Scattered memory accessQuestion 13
What is the difference between std::make_unique and std::make_shared?
// make_unique: separate allocation for object and control block
auto unique = std::make_unique<Widget>(args); // 1 allocation
// make_shared: single allocation for both object and control block
auto shared = std::make_shared<Widget>(args); // 1 allocation
// Manual shared_ptr construction: 2 allocations!
auto manual_shared = std::shared_ptr<Widget>(new Widget(args));Question 14
What is memory compaction or defragmentation?
Question 15
What is a bump pointer allocator?
class BumpAllocator {
char* start;
char* current;
char* end;
public:
BumpAllocator(void* memory, size_t size)
: start(static_cast<char*>(memory)),
current(start),
end(start + size) {}
void* allocate(size_t size, size_t alignment = alignof(std::max_align_t)) {
void* ptr = std::align(alignment, size, reinterpret_cast<void*&>(current),
reinterpret_cast<size_t&>(end - current));
if (!ptr) return nullptr;
current = static_cast<char*>(ptr) + size;
return ptr;
}
void reset() { current = start; }
};Question 16
What is the difference between stack and heap allocation?
// Stack allocation: automatic, fast, limited scope
void func() {
int stack_var = 42; // Stack allocated
MyClass obj(args); // Stack allocated
} // Automatically destroyed
// Heap allocation: manual, slower, flexible lifetime
void func2() {
int* heap_var = new int(42); // Heap allocated
MyClass* obj = new MyClass(args); // Heap allocated
delete heap_var; // Manual cleanup required
delete obj;
}Question 17
What is reference counting in smart pointers?
std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
// Reference count = 1
std::shared_ptr<int> ptr2 = ptr1; // Copy
// Reference count = 2
ptr1.reset(); // ptr1 no longer owns
// Reference count = 1
ptr2.reset(); // ptr2 no longer owns
// Reference count = 0 -> object destroyedQuestion 18
What is memory-mapped I/O and its relation to memory management?
Question 19
What is the difference between weak_ptr and shared_ptr?
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // Doesn't increase ref count
if (auto locked = weak.lock()) { // Try to get shared_ptr
// Use *locked - object still exists
} else {
// Object was destroyed
}
// weak_ptr doesn't prevent destruction
shared.reset(); // Object destroyed hereQuestion 20
What is cache prefetching and its impact on memory management?
// Software prefetching hint
void process_array(int* data, size_t size) {
for (size_t i = 0; i < size; ++i) {
__builtin_prefetch(&data[i + 16]); // Prefetch next cache line
process(data[i]);
}
}Question 21
What is the purpose of std::allocator_traits?
template <typename Alloc>
void use_allocator(const Alloc& alloc) {
using Traits = std::allocator_traits<Alloc>;
// Get pointer type
using pointer = typename Traits::pointer;
// Allocate space for 10 elements
pointer ptr = Traits::allocate(alloc, 10);
// Construct objects
Traits::construct(alloc, ptr, value);
// Destroy and deallocate
Traits::destroy(alloc, ptr);
Traits::deallocate(alloc, ptr, 10);
}Question 22
What is memory overcommitment and its implications?
Question 23
What is the difference between std::unique_ptr and raw pointers?
void func() {
int* raw = new int(42);
// Manual cleanup required
delete raw;
}
void func2() {
std::unique_ptr<int> smart(new int(42));
// Automatic cleanup when goes out of scope
} // Automatically deletedQuestion 24
What is NUMA (Non-Uniform Memory Access) awareness?
Question 25
What is the purpose of std::pmr (Polymorphic Memory Resources)?
#include <memory_resource>
std::pmr::monotonic_buffer_resource buffer(1024);
std::pmr::vector<int> vec(&buffer); // Uses arena allocation
// Different containers can share same memory resource
std::pmr::string str(&buffer);
std::pmr::unordered_map<int, int> map(&buffer);Question 26
What is memory leak detection and prevention?
// RAII prevents leaks
auto resource = std::make_unique<Resource>();
// Smart pointers prevent leaks
std::shared_ptr<Data> shared = std::make_shared<Data>();
// Tools like Valgrind/ASan detect leaks
// Prevention: RAII, smart pointers, careful ownershipQuestion 27
What is the difference between internal and external padding in data structures?
struct InternalPadding {
char c; // 1 byte
// 3 bytes padding for alignment
int i; // 4 bytes
// Total: 8 bytes
};
struct ExternalPadding {
InternalPadding data;
// Add external padding to avoid false sharing
char padding[56]; // Fill cache line
};Question 28
What is garbage collection vs manual memory management?
Question 29
What is memory pool fragmentation and how to avoid it?
class FragmentedPool {
std::vector<void*> free_blocks;
// allocate() removes from free_blocks
// deallocate() adds to free_blocks
// Problem: scattered free blocks create fragmentation
};
class DefragmentedPool {
std::deque<bool> used; // Track contiguous usage
char* pool;
// allocate() finds contiguous free region
// Avoids fragmentation by maintaining contiguous free space
};Question 30
What is the purpose of alignas specifier?
struct alignas(64) CacheLineAligned {
int data;
// Ensures structure starts at 64-byte boundary
};
// Runtime alignment
void* aligned_ptr = std::aligned_alloc(64, size);
// Check alignment
bool is_aligned = (reinterpret_cast<uintptr_t>(ptr) % 64) == 0;Question 31
What is the difference between malloc/free and new/delete?
// C-style: no construction/destruction
int* arr = (int*)malloc(10 * sizeof(int));
free(arr); // No destructor calls
// C++-style: calls constructors/destructors
int* arr2 = new int[10]; // Calls default constructors
double* arr3 = new double[10]{1.0, 2.0}; // Calls constructors with values
delete[] arr2; // Calls destructors
delete[] arr3;Question 32
What is memory-mapped file I/O performance characteristics?
Question 33
What is the purpose of std::weak_ptr::expired()?
std::weak_ptr<int> weak;
{
auto shared = std::make_shared<int>(42);
weak = shared;
std::cout << weak.expired(); // false - object exists
}
std::cout << weak.expired(); // true - object destroyedQuestion 34
What is slab allocation?
class SlabAllocator {
struct Slab {
char* memory;
std::vector<bool> used;
size_t object_size;
};
std::vector<Slab> slabs;
void* allocate(size_t size) {
// Find slab with free slot or create new slab
for (auto& slab : slabs) {
if (slab.object_size == size) {
auto free_slot = std::find(slab.used.begin(), slab.used.end(), false);
if (free_slot != slab.used.end()) {
*free_slot = true;
return &slab.memory[std::distance(slab.used.begin(), free_slot) * size];
}
}
}
// Create new slab...
}
};Question 35
What is the difference between std::shared_ptr thread safety guarantees?
std::shared_ptr<int> ptr = std::make_shared<int>(42);
// Thread-safe: reference counting
std::thread t1([ptr]() { auto p = ptr; }); // OK
std::thread t2([ptr]() { auto p = ptr; }); // OK
// Not thread-safe: pointed-to object
std::thread t3([ptr]() { *ptr = 1; }); // Race condition!
std::thread t4([ptr]() { *ptr = 2; }); // Race condition!Question 36
What is virtual memory and its relation to physical memory?
Question 37
What is the purpose of std::unique_ptr custom deleters?
auto file_deleter = [](FILE* f) {
if (f) {
std::cout << "Closing file\n";
fclose(f);
}
};
std::unique_ptr<FILE, decltype(file_deleter)> file_ptr(
fopen("data.txt", "r"), file_deleter);
// File automatically closed when file_ptr goes out of scopeQuestion 38
What is memory access pattern optimization?
// Bad: scattered access
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N; ++j) {
sum += matrix[j][i]; // Column-major access on row-major array
}
}
// Good: linear access
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N; ++j) {
sum += matrix[i][j]; // Row-major access on row-major array
}
}Question 39
What is the difference between std::make_shared and direct shared_ptr construction?
// Efficient: single allocation
auto ptr1 = std::make_shared<int>(42);
// Inefficient: two allocations
std::shared_ptr<int> ptr2(new int(42));
// Why: make_shared allocates object + control block together
// Direct construction allocates separately, then constructs control blockQuestion 40
What are the fundamental principles for effective memory management in C++?
