一、new构造过程
在使用new关键词创建一个对象指针时,需要做以下工作:
- 使用operater new分配内存; A *pa = static<A *>(operator new(sizeof(A)));
- 然后调用类构造函数; pa->A();
- 返回内存指针。 return pa;
C++提供了默认的operator new函数共用三个版本:
- operator new(size_t); 如果分配内存失败,则抛出异常,同时返回null指针,可以被重载;
- operator new(size_t,const std::nothrow_t&) throw();如果失败不抛出异常,返回null指针,可以被重载;
- void* operator new (std::size_t size, void* ptr) throw(); 该版本为placement new,不能被重载。
在类A中如果重载1、2调用时会调用重载版本,否则会调用系统默认版本。 placement new版本可以将在指定内存中创建对象,ptr就是已分配内存的指针。
二、placement new用法
placement new使用步骤如下:
- 先创建一块内存,该内存足够放下类对象;(const char *constPtr = new char[sizeof(A)];)
- 使用placement new函数创建;A *pa = new (constPtr)A;
- 显式释放pa;pa->~A();
- 如果不用constPtr,释放它; delete []constPtr ;
如下代码:
#include <iostream>
#include <functional>
#include <tuple>
#include <array>
#include "myfunctional.h"
using namespace std;
class B
{
public:
~B()
{
cout << "~B" << endl;
}
};
class A
{
public:
A(int _a, string _s) :a(_a), s(_s), b(new B) {}
~A()
{
delete b;
cout << "~A" << endl;
}
void print()
{
cout << "a = " << a << ", s = " << s.c_str() << endl;
}
private:
int a;
string s;
B *b;
};
int main()
{
char *ptr = new char[sizeof(A)];
A *pa = new ((void *)ptr)A(4,"cjff");
pa->print();
pa->~A();
delete []ptr;
system("pause");
return 0;
}
placement new好处是可以避免频繁new内存,操作过多会有产生大量内存碎片,缺页率会增大,导致程序性能下降和不稳定。
三、注意事项
请看下面的使用方式:
int main()
{
A *ptr = new A(0, "");
A *pa = new ((void *)ptr)A(4,"cjff");
pa->print();
pa->~A();
delete ptr;
system("pause");
return 0;
}
上面代码在delete ptr处会引起崩溃。原因是因为pa和ptr指针指向了同样一块内存(pa和ptr是是同一个东西),当执行pa->~A(),会删除掉pa中成员b的内存,调用delete ptr会重复删除b指向的内存。 故预分配的内存最好是通过new char[]进行。
参考: