new关键字创建出来的对象位于什么地方?
你会直接回答在堆空间内吗,有没有想过会在其他地方,比如在静态存储区。
让我来分析一下你就明白了。
首先我们要明确的是:
– new/delete 的本质其实是 C++ 预定义的操作符
– C++对这两个操作符做了严格的定义行为
new:
- 获取足够大的内存空间(默认为堆空间)
- 在获取的空间中调用构造函数创建对象
delete:
- 调用析构函数销毁对象
- 归还对象所占用的空间(默认为堆空间)
既然 new 和 delete 是操作符,那我们在 C++ 中就可以对其进行重载
- 全局重载(不推荐)
- 局部重载(针对具体类进行重载)
(重载 new 和 delet 的意义在于,改变动态对象创建时的内存分配方式)
那怎么重载
// 不论你写不写static,他都是静态函数
// static member function
void* operator new(unsigned int size)
{
void* ret = NULL;
// ret point to allocated memory
return ret;
}
// static member function
void operator delete(void* p)
{
// free the memory which is pointed by p
}
我们试试在静态存储区里创建动态对象,使 new 出来的对象不再堆空间,而是在静态存储区。
#include<iostream>
using namespace std;
class Test
{
static char c_buffer[];
static char c_map[];
static const unsigned int count = 4;
public:
Test() {}
void* operator new(unsigned int size)
{
void* ret = NULL;
for(int i =0;i<count;i++)
{
if(0 == c_map[i])
{
//做标记,这个空间被用了
c_map[i] = 1;
//返回将要分配空间的地址
ret = c_buffer + sizeof(Test) * i;
cout<<"success new"<<endl;
break;
}
}
return ret;
}
void operator delete(void* p)
{
//空指针就不管它了
if(p!=NULL)
{
char* mem = reinterpret_cast<char*>(p);
//找下标
int index = (mem - c_buffer) / sizeof(Test);
//下标不一定是对的
int flag = (mem - c_buffer) % sizeof(Test);
cout<<"index:"<<index<<endl;
cout<<"flag:"<<flag<<endl;
//满足条件才释放
if((flag==0)&&(0<=index)&&(index<count))
{
//标记要改为未使用
c_map[index] = 0;
cout<<"success to free memory"<<endl;
}
}
}
};
//静态成员类外初始化
char Test::c_buffer[sizeof(Test)*Test::count] = {0};
char Test::c_map[Test::count] = {0};
int main()
{
/* single test */
// 这个对象是在 c_buffer 处生成的,而 c_buffer 处在静态存储区
// 所以这个对象是在静态存储区生成的哦
cout<< "===== single test ====="<<endl;
Test* pt = new Test;
delete pt;
/* array test */
// 实际上这里我们只能生成 4 个对象哦,
cout<< "===== array test ====="<<endl;
Test* pa[6] = {0};
for(int i =0 ;i<6;i++)
{
pa[i] = new Test;
cout<< "pa["<<i<<"]"<<pa[i]<<endl<<endl;
}
for(int i =0 ;i<6;i++)
{
cout<< "delete pa["<<i<<"]"<<pa[i]<<endl<<endl;
delete pa[i];
}
return 0;
}
是不是觉得很神奇。这个方法可以规定这个类能产生多少个对象。
能不能做到在指定的地址上创建C++对象?
解决方案
- 在类中重载 new / delete 操作符
- 在 new 的操作符重载函数中返回指定的地址
- 在 delete 操作符重载中标记对应的地址可用
#include<iostream>
#include<cstdlib> //提供 malloc calloc free
using namespace std;
class Test
{
static char* c_buffer; //指定空间的首地址
static char* c_map; //当指定空间后用来标记是否被使用
static unsigned int count; //指定空间能创建的对象数量
int value; //32位机上占4字节
public:
Test() {}
// 用来设置空间的函数
static bool setMemorySource(char* memory,unsigned int size)
{
bool ret = false;
// 看给的空间够创建几个对象
count = size / sizeof(Test);
ret = (count && (c_map = reinterpret_cast<char*>(calloc(count,sizeof(char)))));
if(ret)
{
// 可以创建对象就让他创建对象呗
c_buffer = memory;
cout<<"setMemorySource success!"<<endl;
}
else {
// 没法创建对象就只能把之前申请的空间释放并清零咯
free(c_map);
c_buffer = NULL;
c_map = NULL;
count = 0;
cout<<"setMemorySource failed!"<<endl;
}
return ret;
}
void* operator new(unsigned int size)
{
void* ret = NULL;
if( count > 0 )
{
//有指定的空间就在指定空间里分配
for(int i =0;i<count;i++)
{
if(0 == c_map[i])
{
//做标记,这个空间被用了
c_map[i] = 1;
//返回将要分配空间的地址
ret = c_buffer + sizeof(Test) * i;
cout<<"success new"<<endl;
break;
}
}
}
else
{
// 可能没指定空间,或者之前指定的空间不满足创建对象的要求
// 这时就直接 malloc 咯
ret = malloc(size);
}
return ret;
}
void operator delete(void* p)
{
//空指针就不管它了
if(p!=NULL)
{
if(count>0)
{
char* mem = reinterpret_cast<char*>(p);
//找下标
int index = (mem - c_buffer) / sizeof(Test);
//下标不一定是对的
int flag = (mem - c_buffer) % sizeof(Test);
cout<<"index:"<<index<<endl;
cout<<"flag:"<<flag<<endl;
//满足条件才释放
if((flag==0)&&(0<=index)&&(index<count))
{
//标记要改为未使用
c_map[index] = 0;
cout<<"success to free memory"<<endl;
}
}
else
{
free(p);
}
}
}
};
//静态成员类外初始化
char* Test::c_buffer = NULL;
char* Test::c_map = NULL;
unsigned int Test::count = 0;
int main()
{
// 我们先自定义一块空间
// char buffer[24] = {0};
char buffer[12] = {0};
// char buffer[1] = {0};
// 把这块空间设置进去
Test::setMemorySource(buffer,sizeof(buffer));
Test* pa[6] = {0};
for(int i =0 ;i<6;i++)
{
pa[i] = new Test;
cout<< "pa["<<i<<"]"<<pa[i]<<endl<<endl;
}
for(int i =0 ;i<6;i++)
{
cout<< "delete pa["<<i<<"]"<<pa[i]<<endl<<endl;
delete pa[i];
}
return 0;
}