C++ Dynamic Memory Quiz
Comprehensive C++ quiz exploring dynamic memory management including new/delete operators, array allocation, memory leaks, dangling pointers, and the motivation for smart pointers in modern C++.
Question 1
When allocating memory dynamically using the new operator for a single object, what happens if the allocation fails and how should this be handled in robust C++ code?
#include <iostream>
#include <new> // For std::bad_alloc
int main() {
try {
int* ptr = new int(42);
std::cout << "Allocation successful: " << *ptr << std::endl;
delete ptr;
} catch(const std::bad_alloc& e) {
std::cout << "Allocation failed: " << e.what() << std::endl;
}
return 0;
}Question 2
What is the most critical difference between new/delete and new[]/delete[] operators when managing dynamically allocated arrays?
Question 3
When does a dangling pointer occur in dynamic memory management, and what are the immediate consequences of dereferencing such a pointer?
#include <iostream>
int main() {
int* ptr = new int(42);
std::cout << "Before delete: " << *ptr << std::endl;
delete ptr; // Memory freed, but ptr still points there
// ptr is now a dangling pointer!
// *ptr; // UNDEFINED BEHAVIOR - could crash or show garbage
ptr = nullptr; // Good practice: set to null after delete
return 0;
}Question 4
What is a memory leak in the context of dynamic memory allocation, and why is it particularly problematic in long-running applications?
Question 5
What fundamental problem with manual memory management using new/delete led to the development of smart pointers in C++?
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource acquired" << std::endl; }
~Resource() { std::cout << "Resource released" << std::endl; }
};
void riskyFunction() {
Resource* res = new Resource();
// What if exception thrown here?
// Resource would leak!
doSomethingThatMightThrow();
delete res; // This might never execute
}
int main() {
try {
riskyFunction();
} catch(...) {
std::cout << "Exception caught, but resource leaked!" << std::endl;
}
return 0;
}Question 6
When using new[] to allocate an array of objects with constructors, what additional memory overhead is typically required and why?
Question 7
What is the most dangerous consequence of mixing new[] with delete instead of delete[] for array deallocation?
#include <iostream>
class TestClass {
public:
TestClass() { std::cout << "Constructor" << std::endl; }
~TestClass() { std::cout << "Destructor" << std::endl; }
};
int main() {
TestClass* arr = new TestClass[3]; // Calls 3 constructors
// delete arr; // WRONG: only calls 1 destructor, leaks 2 objects
delete[] arr; // CORRECT: calls all 3 destructors
return 0;
}Question 8
In a function that allocates memory with new and returns a pointer to it, what ownership transfer responsibility must be clearly documented?
Question 9
What happens when an exception is thrown between new allocation and corresponding delete in a function, and how does this create memory leaks?
#include <iostream>
#include <stdexcept>
void leakyFunction() {
int* ptr1 = new int(1);
// Allocation successful
std::cout << "First allocation: " << *ptr1 << std::endl;
// Simulate some work that might fail
throw std::runtime_error("Something went wrong!");
// This code never executes!
int* ptr2 = new int(2); // Never reached
delete ptr1; // Never reached - LEAK!
delete ptr2; // Never reached
}
int main() {
try {
leakyFunction();
} catch(const std::exception& e) {
std::cout << "Exception: " << e.what() << std::endl;
// Memory leaked!
}
return 0;
}Question 10
Why do smart pointers provide better exception safety compared to raw pointers with manual memory management?
Question 11
What is the primary reason that placement new requires manual destructor calls for proper cleanup?
#include <iostream>
#include <new> // For placement new
class Test {
public:
Test() { std::cout << "Constructor" << std::endl; }
~Test() { std::cout << "Destructor" << std::endl; }
};
int main() {
char buffer[sizeof(Test)];
Test* obj = new (buffer) Test(); // Placement new
// Manual destructor call required!
obj->~Test();
// No delete - memory wasn't allocated by new
return 0;
}Question 12
When implementing a custom memory allocator that uses placement new, what destructor calling pattern ensures proper cleanup of constructed objects?
Question 13
What is the most significant performance overhead introduced by frequent dynamic memory allocations in performance-critical code?
Question 14
In a multi-threaded program where multiple threads allocate and deallocate memory concurrently, what synchronization mechanism prevents heap corruption?
Question 15
When designing a class that manages dynamic memory, what destructor implementation ensures proper cleanup regardless of how the object is destroyed?
#include <iostream>
class MemoryManager {
private:
int* data;
size_t size;
public:
MemoryManager(size_t s) : data(new int[s]), size(s) {
std::cout << "Allocated " << size << " integers" << std::endl;
}
~MemoryManager() {
delete[] data; // Always called, even with exceptions
std::cout << "Deallocated memory" << std::endl;
}
};
int main() {
MemoryManager mgr(100);
// Destructor automatically called when mgr goes out of scope
return 0;
}Question 16
What is the fundamental design principle that smart pointers implement to solve manual memory management problems?
Question 17
When implementing a container class that holds pointers to dynamically allocated objects, what ownership model prevents memory leaks?
Question 18
What is the most effective strategy for detecting memory leaks in large C++ applications during development?
Question 19
When converting legacy code that uses raw pointers to smart pointers, what is the most challenging aspect of the migration process?
Question 20
What is the primary advantage of using std::unique_ptr over raw pointers for exclusive ownership scenarios?
#include <iostream>
#include <memory>
class Resource {
public:
Resource() { std::cout << "Resource created" << std::endl; }
~Resource() { std::cout << "Resource destroyed" << std::endl; }
};
std::unique_ptr<Resource> createResource() {
return std::unique_ptr<Resource>(new Resource());
}
int main() {
auto res = createResource();
// Automatic cleanup when res goes out of scope
return 0;
}Question 21
In a program that needs to allocate memory in a loop, what allocation strategy minimizes heap fragmentation and improves performance?
Question 22
What is the most critical consideration when overriding operator new and operator delete for a class?
Question 23
When implementing a memory pool allocator, what bookkeeping information must be tracked for each allocation?
Question 24
What is the fundamental problem that nothrow new attempts to solve in memory allocation?
#include <iostream>
#include <new> // For nothrow
int main() {
// Standard new - throws on failure
try {
int* ptr1 = new int;
delete ptr1;
} catch(const std::bad_alloc&) {
std::cout << "Standard new failed" << std::endl;
}
// Nothrow new - returns nullptr on failure
int* ptr2 = new (std::nothrow) int;
if(!ptr2) {
std::cout << "Nothrow new failed" << std::endl;
} else {
delete ptr2;
}
return 0;
}Question 25
In a real-time system where memory allocation timing must be predictable, what allocation strategy should be avoided?
Question 26
What is the most significant advantage of using std::shared_ptr over manual reference counting for shared ownership?
Question 27
When implementing a custom deleter for smart pointers, what is the most important design consideration?
#include <iostream>
#include <memory>
#include <cstdio> // For fopen/fclose
int main() {
// Custom deleter for FILE*
auto fileDeleter = [](FILE* f) {
if(f) fclose(f);
};
std::unique_ptr<FILE, decltype(fileDeleter)> file(
fopen("test.txt", "w"), fileDeleter);
if(file) {
fprintf(file.get(), "Hello, World!");
}
// File automatically closed by custom deleter
return 0;
}Question 28
What is the primary reason that memory-mapped I/O requires different memory management strategies than heap allocation?
Question 29
In a program that needs to allocate memory with specific alignment requirements, what is the most portable approach using standard C++?
Question 30
What is the most challenging aspect of debugging memory corruption caused by buffer overflows in dynamically allocated memory?
Question 31
When designing a memory allocator for a high-throughput server application, what is the most important performance consideration?
Question 32
What is the fundamental principle behind garbage collection that smart pointers partially implement?
Question 33
In a program that needs to transfer ownership of dynamically allocated objects between functions, what smart pointer operation provides the most efficient transfer mechanism?
#include <iostream>
#include <memory>
std::unique_ptr<int> createObject() {
return std::unique_ptr<int>(new int(42));
}
void processObject(std::unique_ptr<int> obj) {
std::cout << "Processing: " << *obj << std::endl;
// Ownership automatically transferred and cleaned up
}
int main() {
auto obj = createObject();
processObject(std::move(obj)); // Efficient ownership transfer
// obj is now empty
return 0;
}Question 34
What is the most significant limitation of std::auto_ptr compared to modern smart pointers?
Question 35
When implementing a resource manager that must clean up multiple types of resources, what smart pointer feature provides the most flexible cleanup mechanism?
