C++ new关键字运算符重载
#include <iostream> #include <vector> #include <list> class MyClass { public: // 构造函数 MyClass(int value) : data(value) { std::cout << "MyClass constructor called with value " << data << std::endl; } // 析构函数 ~MyClass() { std::cout << "MyClass destructor called" << std::endl; } // 静态成员函数,用于重载new void* operator new(size_t size) { void* p = malloc(size); std::cout << "Custom new called for MyClass, allocating " << size << " bytes at " << p << std::endl; return p; } // 静态成员函数,用于重载delete void operator delete(void* p) noexcept { std::cout << "Custom delete called for MyClass, freeing memory at " << p << std::endl; free(p); } int data; std::list<int> arr; }; int main() { MyClass* ptr = new MyClass(42); ptr->arr.push_back(1); delete ptr; return 0; }
在C++中,当你使用new运算符(无论是重载版本还是默认版本)来创建类的对象时,对象的构造函数会在分配内存之后、但在将内存地址返回给调用者之前被调用。这确保了对象在使用之前被正确地初始化。
上述例子发生的事情的顺序如下
MyClass::operator new(size_t size)被调用以在堆上分配足够的内存来存储MyClass对象。
分配的内存地址(由malloc或其他内存分配函数返回)被传递给构造函数MyClass(int value)。
MyClass(int value)构造函数在分配的内存上被调用,并使用提供的参数42来初始化对象。
构造函数完成后,new表达式返回指向新创建并初始化的对象的指针。
因此,构造函数是在内存分配之后但在将指针返回给调用者之前被调用的。这是确保对象在使用之前处于有效状态的重要步骤。
需要注意的是,如果你重载了new运算符但没有正确地处理内存分配失败的情况(例如,没有检查malloc的返回值是否为nullptr),并且内存分配失败,那么构造函数将不会被调用,因为根本没有分配内存来存储对象。
在这种情况下,你应该让重载的new运算符抛出异常(如std::bad_alloc),以便调用者可以适当地处理内存分配失败的情况。