new有三种调用形式
//throwing (1)
void* operator new (std::size_t size);
//nothrow (2)
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
//placement (3)
void* operator new (std::size_t size, void* ptr) noexcept;
(1) throwing allocation
分配 size bytes的储存空间,适当对齐以表示该大小的任何对象,返回一个指向这片储存块最前面一位的非空指针。若失败,返回一个 bad_alloc 异常。
(2) nothrow allocation
同1,区别在于失败后返回一个空指针而非bad_alloc异常
(3) placement
仅仅返回ptr。没有储存空间被分配。
请注意:本函数被一个新的表达式调用时,合适的初始化函数会被调用,如被类对象对用,本函数会调用类的默认构造函数。
delelte有五种调用形式(c++14)
//ordinary (1)
void operator delete (void* ptr) noexcept;
//nothrow (2)
void operator delete (void* ptr, const std::nothrow_t& nothrow_constant) noexcept;
//placement (3)
void operator delete (void* ptr, void* voidptr2) noexcept;
//with size (4)
void operator delete (void* ptr, std::size_t size) noexcept;
//nothrow with size (5)
void operator delete (void* ptr, std::size_t size, const std::nothrow_t& nothrow_constant) noexcept;
(1) ordinary delete
析构由ptr指针(若非空,空的话异常)指向的空间,释放有之前调用new开辟的内存空间。并把该指针置为无效。
(2) nothrow delete
同1,默认调用的是1,声明了方便重载。对应new的(2)
(3) placement delete
啥也不干。对应new的(3)
(4) (5) with size
与(1) (2) 相似,它们为自定义实现提供了一个优化点:使用与调用相应分配函数相同的size参数来调用它们。
new和delete具有的特性
- 全局性:在全局命名空间中定义,并不是在std命名空间中
- 隐式的:(1)(2)调用方法在每一个c++的翻译单元中都已经被隐式声明,不需要而外include new 头文件
- 可替换的:(1)(2)是可以被替换或重载的
set_new_handler
可以修改1,2的异常函数
operator new/delete 与new/delete 区别
operator new可以被显式调用,但在c++中,new是一个有特定表现的操作:
一个表达是调用new,将首先调用函数 operator new,调用参数取决于表达式里的类型大小。
然后调用该类型的构造函数。最后将返回的指针转换成对应类型的指针。
简单来说,就是new里面内置调用了operator new开辟空间分配内存,并把这片内存初始化为对应的类型(通过调用对应的构造函数),再返回对应类型的指针。operator new和operator delete这两个全局函数相当于c的malloc和free
理解了new,delelte是对应的
operator delete可以被显式调用,但在c++中,delete是一个有特定表现的操作:
delete先调用对应类型的析构函数,然后调用operator delete。
实例
// operator new example
#include <iostream> // std::cout
#include <new> // ::operator new
struct MyClass {
int data[100];
MyClass() {std::cout << "constructed [" << this << "]\n";}
};
int main () {
std::cout << "1: ";
MyClass * p1 = new MyClass;
// allocates memory by calling: operator new (sizeof(MyClass))
// and then constructs an object at the newly allocated space
std::cout << "2: ";
MyClass * p2 = new (std::nothrow) MyClass;
// allocates memory by calling: operator new (sizeof(MyClass),std::nothrow)
// and then constructs an object at the newly allocated space
std::cout << "3: ";
new (p2) MyClass;
// does not allocate memory -- calls: operator new (sizeof(MyClass),p2)
// but constructs an object at p2
// Notice though that calling this function directly does not construct an object:
std::cout << "4: ";
MyClass * p3 = (MyClass*) ::operator new (sizeof(MyClass));
// allocates memory by calling: operator new (sizeof(MyClass))
// but does not call MyClass's constructor
delete p1;
delete p2;
delete p3;
return 0;
}
输出结果(内存分配不同,后面的数据不同)
1: constructed [0x8f0f70]
2: constructed [0x8f23a8]
3: constructed [0x8f23a8]
4: