之前在别人的面经中看到了有面试官会问:new operator
, operator new
和placement new
的区别。(根本没在学习C++的时候了解过这个东西)所以特此记录一下。
C++三种内存管理的基本案例
1. new operator (new操作符)
new operator做了两件事:
- 调用operator new分配内存;
- 在分配的内存上调用构造函数。
1 2
| MyClass* obj = new MyClass(args);
|
2. operator new (new操作符函数)
operator new等价于malloc,只分配了内存不会调用构造函数。
1 2 3 4 5
| void* ptr = operator new(sizeof(MyClass));
void* ptr = malloc(sizeof(MyClass));
|
3. placement new (定位new)
1 2 3 4 5 6 7
| char buffer[sizeof(MyClass)]; MyClass* obj = new(buffer) MyClass(args);
void* memory = operator new(sizeof(MyClass)); MyClass* obj = new(memory) MyClass(args);
|
所以,如果想要使用这个对象。一般直接new operator。要么就是operator new + placement new这个组合来实例化对象。
🔍 详细分析和示例
1. new operator - 完整的对象创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream>
class MyClass { int value; public: MyClass(int v) : value(v) { std::cout << "Constructor called, value = " << value << std::endl; } ~MyClass() { std::cout << "Destructor called, value = " << value << std::endl; } void print() const { std::cout << "Value: " << value << std::endl; } };
void demo_new_operator() { std::cout << "=== new operator demo ===" << std::endl; MyClass* obj = new MyClass(42); obj->print(); delete obj; }
|
new operator的内部过程:
1 2 3 4 5 6 7 8 9 10 11 12 13
| MyClass* obj; try { void* memory = operator new(sizeof(MyClass)); obj = new(memory) MyClass(42); } catch(...) { operator delete(memory); throw; }
|
2. operator new - 纯内存分配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <new> #include <iostream>
void demo_operator_new() { std::cout << "=== operator new demo ===" << std::endl; void* raw_memory = operator new(sizeof(MyClass)); std::cout << "Memory allocated at: " << raw_memory << std::endl; MyClass* obj = new(raw_memory) MyClass(100); obj->print(); obj->~MyClass(); operator delete(raw_memory); }
|
自定义operator new:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class CustomMemoryClass { int data; public: CustomMemoryClass(int d) : data(d) { std::cout << "Constructor: " << data << std::endl; } ~CustomMemoryClass() { std::cout << "Destructor: " << data << std::endl; } static void* operator new(size_t size) { std::cout << "Custom operator new called, size = " << size << std::endl; void* ptr = malloc(size); if (!ptr) throw std::bad_alloc(); return ptr; } static void operator delete(void* ptr) { std::cout << "Custom operator delete called" << std::endl; free(ptr); } void print() const { std::cout << "Data: " << data << std::endl; } };
void demo_custom_operator_new() { std::cout << "=== Custom operator new demo ===" << std::endl; CustomMemoryClass* obj = new CustomMemoryClass(200); obj->print(); delete obj; }
|
3. placement new - 在指定位置构造对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <new> #include <memory>
void demo_placement_new() { std::cout << "=== Placement new demo ===" << std::endl; alignas(MyClass) char buffer[sizeof(MyClass)]; MyClass* obj1 = new(buffer) MyClass(300); obj1->print(); obj1->~MyClass(); void* memory = operator new(sizeof(MyClass)); MyClass* obj2 = new(memory) MyClass(400); obj2->print(); obj2->~MyClass(); operator delete(memory); const int count = 3; alignas(MyClass) char array_buffer[sizeof(MyClass) * count]; MyClass* objects = reinterpret_cast<MyClass*>(array_buffer); for (int i = 0; i < count; ++i) { new(objects + i) MyClass(500 + i); } for (int i = 0; i < count; ++i) { objects[i].print(); } for (int i = count - 1; i >= 0; --i) { objects[i].~MyClass(); } }
|
🎯 实际使用场景
1. 内存池实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| template<typename T, size_t PoolSize> class MemoryPool { alignas(T) char pool[sizeof(T) * PoolSize]; bool used[PoolSize]; public: MemoryPool() { std::fill(used, used + PoolSize, false); } template<typename... Args> T* construct(Args&&... args) { for (size_t i = 0; i < PoolSize; ++i) { if (!used[i]) { used[i] = true; return new(pool + i * sizeof(T)) T(std::forward<Args>(args)...); } } throw std::bad_alloc(); } void destroy(T* obj) { size_t index = (reinterpret_cast<char*>(obj) - pool) / sizeof(T); if (index < PoolSize && used[index]) { obj->~T(); used[index] = false; } } };
void demo_memory_pool() { std::cout << "=== Memory Pool demo ===" << std::endl; MemoryPool<MyClass, 10> pool; MyClass* obj1 = pool.construct(600); MyClass* obj2 = pool.construct(700); obj1->print(); obj2->print(); pool.destroy(obj1); pool.destroy(obj2); }
|
2. 自定义容器实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| template<typename T> class SimpleVector { T* data; size_t size_; size_t capacity_; public: SimpleVector() : data(nullptr), size_(0), capacity_(0) {} ~SimpleVector() { clear(); operator delete(data); } void push_back(const T& value) { if (size_ >= capacity_) { reserve(capacity_ == 0 ? 1 : capacity_ * 2); } new(data + size_) T(value); ++size_; } void reserve(size_t new_capacity) { if (new_capacity <= capacity_) return; T* new_data = static_cast<T*>(operator new(sizeof(T) * new_capacity)); for (size_t i = 0; i < size_; ++i) { new(new_data + i) T(std::move(data[i])); data[i].~T(); } operator delete(data); data = new_data; capacity_ = new_capacity; } void clear() { for (size_t i = 0; i < size_; ++i) { data[i].~T(); } size_ = 0; } T& operator[](size_t index) { return data[index]; } const T& operator[](size_t index) const { return data[index]; } size_t size() const { return size_; } };
void demo_custom_vector() { std::cout << "=== Custom Vector demo ===" << std::endl; SimpleVector<MyClass> vec; vec.push_back(MyClass(800)); vec.push_back(MyClass(900)); for (size_t i = 0; i < vec.size(); ++i) { vec[i].print(); } }
|
3. RAII和异常安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| template<typename T> class SafeConstructor { void* memory; T* object; bool constructed; public: template<typename... Args> SafeConstructor(Args&&... args) : memory(nullptr), object(nullptr), constructed(false) { try { memory = operator new(sizeof(T)); object = new(memory) T(std::forward<Args>(args)...); constructed = true; } catch (...) { if (memory) { operator delete(memory); } throw; } } ~SafeConstructor() { if (constructed && object) { object->~T(); } if (memory) { operator delete(memory); } } T* get() { return constructed ? object : nullptr; } T* release() { T* result = object; object = nullptr; constructed = false; return result; } };
|
📊 三者对比总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void comparison_demo() { std::cout << "=== Comparison Demo ===" << std::endl; MyClass* obj1 = new MyClass(1); delete obj1; void* memory = operator new(sizeof(MyClass)); MyClass* obj2 = new(memory) MyClass(2); obj2->~MyClass(); operator delete(memory); alignas(MyClass) char buffer[sizeof(MyClass)]; MyClass* obj3 = new(buffer) MyClass(3); obj3->~MyClass(); }
|
🎯 使用场景总结
方式 |
使用场景 |
优势 |
注意事项 |
new operator |
日常对象创建 |
简单安全,自动管理 |
性能开销,内存碎片 |
operator new |
自定义内存管理 |
灵活控制分配策略 |
需要手动构造对象 |
placement new |
内存池、容器、嵌入式 |
零分配开销,精确控制 |
需要手动析构 |
最佳实践:
- 一般情况:使用
new operator
和智能指针
- 性能关键:考虑内存池 +
placement new
- 自定义容器:
operator new
+ placement new
组合
- 嵌入式系统:
placement new
避免动态分配
这三种方式各有用途。在上层应用级的开发中,直接使用new operator最直接。但是如果想要更细粒度地去分配、管理内存资源,减少一些额外的内存管理开销,就要手动的operator new + placement new两种方法了。