122. Move Assignment Ownership

You are given a C++ class that manages a dynamically allocated array of bytes.
This buffer represents an exclusively owned resource, meaning:

  • At any time, only one object may own the buffer
  • The buffer must never be duplicated
  • Copying ownership is strictly forbidden
  • Ownership transfer must be done using move semantics only

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:

  • Implement a move assignment operator
  • Explicitly disable copy assignment
  • Ensure the destination object releases any previously owned memory
  • Transfer ownership without copying data
  • Leave the moved-from object in a valid, empty state
  • Prevent memory leaks, double frees, or undefined behavior

⚠️ The provided template code intentionally violates exclusive ownership rules and must fail the test cases.
Only a correct implementation will pass.

 

Program Flow

  1. Read integer N
  2. Read N integers and construct object A
  3. Read integer M
  4. Read M integers and construct object B
  5. Execute move assignment: A = std::move(B)
  6. Print contents of A
  7. Print contents of B

 

Expected Behavior After Fix

  • A contains the values originally stored in B
  • B prints No data
  • No deep copy occurs
  • No memory leak or double free occurs
  • Ownership is transferred, not duplicated

 

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 100
  • Memory must be allocated using new[]
  • Memory must be released using delete[]
  • Copy assignment must be explicitly disabled
  • Move assignment must be implemented
  • Output must match exactly (including spacing and newlines)

 

 

 

Need Help? Refer to the Quick Guide below

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.

  • Copy: I photocopy your notes. Now we both have sheets of paper. (Slow)
  • Move: I take the notes from your hand. I have them, you have nothing. (Fast).

Syntax & Usage

1. R-value References (&&)

To distinguish between "Copyable" and "Movable" objects, C++ uses &&.

  • L-value (Type&): A persistent variable (x). You Copy it.
  • R-value (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.

Copy vs. Move Visualization

FeatureCopy (const Type&)Move (Type&&)
OperationDuplicate Data (Deep Copy).Transfer Pointer (Shallow Copy).
Old ObjectRemains valid and unchanged.Valid but Empty (gutted).
CostHigh (alloc + memcpy).Near Zero (pointer assignment).
HardwareDuplicates logic (Bad for drivers).Transfers ownership (Good for drivers).

Relevance in Embedded/Firmware

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.

  • Without Move: Every string is malloc'd and copied. (Slow, heap fragmentation).
  • With Move: Only pointers are swapped. (Fast, no heap churn).

Common Pitfalls (Practical Tips)

PitfallDetails
❌ Use After Move

Accessing an object after moving from it is undefined logic (usually crashes).

auto b2 = std::move(b1); b1.send(); -> Crash (b1 is empty).

std::move doesn't movestd::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.
noexceptAlways 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 FiveIf you write a custom Destructor, you typically need: Copy Ctor, Copy Assign, Move Ctor, Move Assign.