Find and Fix C++ Ownership Bugs: Double Free, Shallow Copy, and Object Slicing
SIG (Susquehanna)Software Engineer · OnsiteLast updated
Tests a candidate's ability to identify and fix critical C++ resource management bugs, specifically shallow copies leading to double-free errors and object slicing caused by improper pass-by-value semantics with polymorphic types.
Scenario
You are reviewing a C++ order processing module written for an internal messaging component. The snippet below manages dynamic memory and uses inheritance for specialized order buffers, but it exhibits serious ownership and polymorphism bugs.
#include
#include
class OrderBuffer {
public:
OrderBuffer(size_t size) : size_(size), data_(new char[size]) {
std::memset(data_, 0, size_);
}
virtual ~OrderBuffer() {
delete[] data_;
}
virtual void process() const {
std::cout << "Processing standard buffer of size " << size_ << "\n";
}
protected:
size_t size_;
char* data_;
};
class PriorityOrderBuffer : public OrderBuffer {
public:
PriorityOrderBuffer(size_t size, int priority)
: OrderBuffer(size), priority_(priority) {}
void process() const override {
std::cout << "Processing priority buffer (priority: "
<< priority_ << ") of size " << size_ << "\n";
}
private:
int priority_;
};
void handleBuffer(OrderBuffer buf) {
buf.process();
}
int main() {
PriorityOrderBuffer pbuf(256, 1);
handleBuffer(pbuf);
return 0;
}
Tasks
- Identify the Bugs: Pinpoint and explain why the code causes undefined behavior (specifically, a double-free) and object slicing.
- Explain the Root Cause: Discuss the Rule of Three/Five violation in
OrderBuffer, and explain what occurs during the invocation ofhandleBuffer(pbuf). - Refactor the Code:
- Provide a corrected version using modern C++ principles (such as RAII, the Rule of Zero, and smart pointers or
std::vector). - Fix the function signature and invocation to properly support polymorphic dispatch without slicing or unnecessary allocations.
- Provide a corrected version using modern C++ principles (such as RAII, the Rule of Zero, and smart pointers or
Hints
Hint 1
Look closely at what happens to the raw pointer member when the compiler synthesizes the copy constructor for OrderBuffer.
Hint 2
Notice how handleBuffer accepts its parameter by value rather than by reference or pointer.
Hint 3
Consider how applying the Rule of Zero using standard library containers or unique ownership eliminates manual delete calls entirely.
Follow-up questions
- How does the copy-and-swap idiom help implement strong exception safety if you must manually manage resources in C++?
- In a high-frequency trading context where dynamic memory allocation on the critical path is prohibited, how would you redesign these buffers to avoid heap allocations entirely?
- What are the performance implications of virtual dispatch (vtable lookups) and cache misses when passing polymorphic objects via pointers or references versus using compile-time polymorphism (e.g., CRTP or `std::variant`)?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.