Question.2
How should a placement-new object be cleaned up?
alignas(Sensor) uint8_t buf[sizeof(Sensor)];
Sensor* s = new (buf) Sensor(5);
// ... done using s ...Standard new allocates memory on the Heap and then constructs the object.
Placement New separates these steps. It allows you to construct an object in a pre-allocated memory buffer (Stack, Static, or a specific hardware address) that you explicitly provide.
This is the standard way to use C++ objects in strict embedded systems where the Heap is banned.
1. Basic Setup
You need a memory buffer (usually a byte array) large enough to hold the object.
Note: You must include <new> to use this.
#include <new>
class Sensor {
public:
int id;
Sensor(int i) : id(i) { printf("Init\n"); }
~Sensor() { printf("De-init\n"); }
};
// 1. Allocate raw memory (Static buffer)
// 'alignas' prevents bus faults by ensuring correct memory alignment
alignas(Sensor) uint8_t buffer[sizeof(Sensor)];
int main() {
// 2. Use Placement New
// Syntax: new (address) Type(args);
Sensor* s = new (buffer) Sensor(10);
// s->id is now 10, stored inside 'buffer'
}2. Manual Destruction
Because you didn't allocate memory with standard new, you cannot use standard delete. You must call the destructor manually.
// ❌ delete s; // CRASH! Tries to free static memory to the heap manager.
s->~Sensor(); // ✅ Correct: Cleans up the object, leaves memory alone.Standard new finds a random spot in the Heap. Placement new puts the object exactly where you say.
| Standard new Sensor() | Placement new (buf) Sensor() |
|---|---|
Step 1: Ask Heap Manager for sizeof(Sensor) bytes. | Step 1: User provides address of buffer. |
| Step 2: Construct object in that heap memory. | Step 2: Construct object in buffer. |
| Result: Pointer to dynamic heap memory. | Result: Pointer to your static buffer. |
1. No Heap Required
You can have full C++ objects (with constructors, v-tables, and inheritance) stored entirely in Static Memory (.bss). This makes your firmware deterministic and fragmentation-free, satisfying safety standards (MISRA, ISO26262).
2. Memory-Mapped Objects
You can place an object directly onto a hardware register or a specific memory region (e.g., backup SRAM or shared memory between cores).
// Construct a Driver object exactly at the hardware address 0x40005000
UART_Driver* uart1 = new (reinterpret_cast<void*>(0x40005000)) UART_Driver();3. Object Pools
If you need to create/destroy objects frequently (e.g., Network Packets), use a pre-allocated array of buffers (a Pool). Use placement new to construct a packet in slot 0, manually destroy it, and then reuse slot 0 for a new packet later.
| Pitfall | Details |
|---|---|
| ❌ Memory Alignment | If your buffer is just Fix: Always use |
❌ Using delete | Calling delete on a placement-new pointer will confuse the memory manager (allocator), likely causing a crash or heap corruption. Always use ptr->~Class(). |
| ❌ Buffer Overrun | You must ensure sizeof(buffer) >= sizeof(Object). The compiler won't warn you if the buffer is too small, leading to memory corruption of adjacent variables. |
| ✅ Reusing Memory | Placement new is perfect for "Union-like" behavior where different types of objects reuse the same memory chunk at different times to save RAM. |