You are given a C++ class that manages a dynamically allocated array of bytes.
This buffer represents an exclusively owned resource, meaning:
Two objects of this class already exist. Your task is to ensure that ownership of the buffer can be safely transferred from one object to another using move assignment.
Your Objectives
You must modify the provided template code to:
⚠️ The provided template code intentionally violates exclusive ownership rules and must fail the test cases.
Only a correct implementation will pass.
Program Flow
NN integers and construct object AMM integers and construct object BA = std::move(B)AB
Expected Behavior After Fix
A contains the values originally stored in BB prints No data
Example Input
4
10 20 30 40 3 1 2 3 Example Output
1 2 3
No data
Constraints
N and M are in the range 1 to 100new[]delete[]
In C++, copying an object (Deep Copy) is expensive—it involves allocating new memory and copying data byte-by-byte.
Move Semantics (introduced in C++11) allows you to transfer ownership of resources (like memory pointers or file handles) from one object to another without copying the actual data.
Think of it as "Stealing" the resources.
1. R-value References (&&)
To distinguish between "Copyable" and "Movable" objects, C++ uses &&.
Type&): A persistent variable (x). You Copy it.Type&&): A temporary object (Type()) or explicitly moved object. You Move it.2. Move Constructor & Assignment
Instead of allocating new RAM, we just copy the pointer and set the old pointer to nullptr.
class Buffer {
uint8_t* ptr;
public:
// Move Constructor
Buffer(Buffer&& other) noexcept {
this->ptr = other.ptr; // 1. Steal the pointer
other.ptr = nullptr; // 2. Nullify the source (Prevent double-free)
}
// Move Assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] ptr; // Free my current memory
this->ptr = other.ptr; // Steal
other.ptr = nullptr; // Nullify
}
return *this;
}
};3. std::move
Forces a move on a named variable.
Buffer b1(100);
Buffer b2 = std::move(b1); // b2 owns the memory. b1 is now empty.| Feature | Copy (const Type&) | Move (Type&&) |
|---|---|---|
| Operation | Duplicate Data (Deep Copy). | Transfer Pointer (Shallow Copy). |
| Old Object | Remains valid and unchanged. | Valid but Empty (gutted). |
| Cost | High (alloc + memcpy). | Near Zero (pointer assignment). |
| Hardware | Duplicates logic (Bad for drivers). | Transfers ownership (Good for drivers). |
1. High-Performance Returns
In C, to avoid copying a large struct, we pass pointers: void get_data(BigStruct* out).
In C++, Move Semantics allow you to return by value efficiently.
// Returns a heavy object (e.g., 1KB buffer)
Packet receive_packet() {
Packet p;
// ... fill p ...
return p; // Compiler automatically Moves this out. Zero overhead.
}
2. Driver Ownership (std::unique_ptr)
Hardware drivers (UART, SPI) are "non-copyable" (you can't clone a physical peripheral). However, you often want to move a driver around (e.g., create it in init() and pass it to a Manager class).
Move semantics allow this safe transfer of ownership without cloning.
3. Container Performance
If you have a std::vector<String>, resizing the vector requires moving all elements to a new memory block.
| Pitfall | Details |
|---|---|
| ❌ Use After Move | Accessing an object after moving from it is undefined logic (usually crashes).
|
❌ std::move doesn't move | std::move(x) generates no code. It effectively just casts x to x&&, telling the compiler "Please try to use the Move Constructor." If you didn't write a Move Constructor, it silently falls back to Copy. |
❌ noexcept | Always mark move constructors as noexcept. If a move can throw an exception, standard containers (like vector) will refuse to use it and will Copy instead. |
| ✅ Rule of Five | If you write a custom Destructor, you typically need: Copy Ctor, Copy Assign, Move Ctor, Move Assign. |