New
今天,我们只讲new。
1. new operator
new操作符(new operator)比较容易理解,相信对C++比较熟悉的人,对下面的代码都不会觉得陌生。这是使用new 最常见的形式。
class A{ .... }; std::shared_ptr<A> a(new A);
new operator实际上就是: 分配内存+调用构造函数初始化。
2. operator new
new operator和operator new虽然差不多,但是你不可以把它们等同起来。与new operator相比,operator new 少了构造初始化的部分,它与malloc比较像。
operator new的声明一般为:
void * operator new(size_t size);
需要注意的是,operator new返回一个未经过处理的指针(类型是void*)。new operator调用operator new来分配内存,operator new也能够被重载。
默认的operator new 重载版本有:
void * operator new(std::size_t count) throw(std::bad_alloc); //normal new void * operator new(std::size_t count, void *ptr)throw(); //placement new void * operator new(std::size_t count, const std::nothrow_t&)throw();//nothrow new, 为了兼容以前的版本
我们来看一下operator new的源码:
void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc) __attribute__((__externally_visible__)); void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc) __attribute__((__externally_visible__));
- _GLIBCXX_THROW: 指定该函数抛出的异常,C++11后该宏为空
- __attribute__: GCC使用__attribute__关键字来描述函数,变量和数据类型的属性,用于编译器对源代码的优化。
- __externally_visible__: GCC的优化参数,详情:https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
3. placement new
所谓定位放置(placement new)就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。
class A{ .... }; int main(){ char mem[100]; A* p=new (mem) A; p->~A(); return 0; }
operator new和placement new的关系:
class A{ .... }; A* p=new A(10);//有参构造 //等同于下面的调用 void* mem=malloc(sizeof(A)); A* p=new (mem) A(10);
看似神奇的placement new实际上是operator new的一个全局重载版本,它实际上做了这么一件事(我们来看一下源码):
// Default placement versions of operator new. inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT { return __p; } inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT { return __p; }
我们可以看到实际上它不加任何处理直接返回了指针。那么函数的两个参数从哪来?
其实,当我们写了下面的代码时:
A* p=new (mem) A;
实际上,转变为了:
operator new (sizeof(A), men);
到这里,就知道上面源码的operator new两个参数是什么了吧。
4. 重写operator new
这部分省略(网上的资料有不少):
https://www.cnblogs.com/cly-blog/p/5984660.html
5. 总结
看到这里,你是否对new operator、operator new、placement new有了一个全面的了解,下面我们来总结一下:
- new operator:分配内存+调用构造函数
- operator new:分配内存
- placement new:在已分配的内存里调用构造函数
- 假设你想定制自己的在堆对象被建立时的内存分配过程,你应该写你自己的operator new函数。然后使用new操作符,new操作符会调用你定制的operator new。
生命中所有的灿烂,终要寂寞偿还。——《百年孤独》