c++内存分配和管理

本文介绍了C和C++中的三种基本存储区域:静态存储区、自动存储区和自由存储区,并详细探讨了new和delete运算符的使用方法及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 感觉这部分比较好,而且非常有用,所以就转过来~

4.1 存储

    在C和C++中,有三种基本的存储使用区:
在静态存储区中,连接器(linker)根据程序的需求为对象分配空间。全局变量、静态类成员以及函数中的静态变量都被分配在该区域中。一个在该区域中分配的对象只被构造一次,其生存期一直维持到程序结束。在程序运行的时候其中的地址是固定不变的。在使用线程(thread,共享地址空间的并发物)的程序里,静态对象可能会引起一些问题,因为这时的静态对象是被共享的,要对其正常访问就需要进行锁定操作。
函数的参数和局部变量被分配在此。对同一个函数或区块的每一处调用,其在该区域内都有自己单独的位置。这种存储被自动创建和销毁;因而才叫做“自动存储区”。自动存储区也被称为是“在上的(be on the stack)”。
在该区域中,程序必须明确的为对象申请空间,并可以在使用完毕之后释放申请到的空间(使用new和delete运算符)。当程序需要其中更多的空间时,就使用new向操作系统提出申请。通常情况下,自由存储区(也被称作动态存储区或者(heap))在一个程序的生存期内是不断增大的,因为其间被其它程序占用的空间从来都不被归还给操作系统。例如:
    在C/C++中,允许在用户程序执行时动态的为对象分配存储。在C中,使用malloc()或calloc()、realloc()、free()来动态的分配、释放存储空间;在C++中,使用new()、delete()来动态的分配、释放存储空间。C++中的new()与C中的malloc()相比,有以下两个优点:
    <1>new()自动返回正确的指针类型,不需要对返回指针进行类型转换。
int *p = newint[20];
<2> new()可以将创建的对象初始化。
int *p = newint(20);
释放内存时,无论是由malloc()还是由new一次性分配的内存空间,必须一次性释放。该内存块可以是n个连续的自定义struct空间或n个连续基本类型空间。
<3>函数中分配内存
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,如下所示
void GetMemory2(char **p, int num)
{
    *p = new char[sizeof(char) * num];
}
void Test2(void)
{
    char *str = NULL;
    GetMemory2(&str, 100); // 注意参数是 &str,而不是str
    strcpy(str, "hello");  
    cout<< str << endl;
    free(str); 
}
 
 
使用new创建对象数组时,不能对各个对象进行初始化。对对象数组中的每一个对象进行初始化有以下两个方法:
<1>定义专门函数来完成初始化(如下表右);
<2>在类中增加不带参数的构造函数来初始化(如下表左)。
 
classpoint {
public:
    intx, y;
    point(intox, intoy);
point();
};
point::point(intox, intoy){
       x = ox;
       y = oy;
    }
point::point(){
       x =10;
       y =10;
}
voidmain()
{
    point *p1 = newpoint(3,3); //声明对象指针,创建对象并调用带参数的构造函数,初始化对象
    point *p2 = newpoint[5]; //声明对象数组指针,创建对象并调用不带参数的构造函数,初始化对象
        delete p1;
    delete []p2;
}
Classpoint {
Public:
    intx, y;
voidsetPoint(int ox, int oy);
};
voidpoint::setPoint(int ox, int oy){
       x = ox;
       y = oy;
    }
 
voidmain()
{
    point *p2 = newpoint[5]; //声明对象数组指针,创建对象
    for(inti=0; i<5; i++)
       p2[i].setPoint(10, 10);//调用setPoint函数对成员变量促使化
delete []p2;
}
 
 
       
类的每个指针成员要么指向有效的内存,要么就指向空,在析构函数里可简单地delete,而不用担心该指针是不是被new过。
使用new()创建多维数组时,必须提供各维的大小。如:
    int (*l)[2];
l= newint[2][2]; //ok
l= newint[2][]; //error
l= newint[][2]; //error
创建两维数组,举例
int **p = newint*[3];//首先分配指针数组中各个指针(p[0],p[1],p[2])的空间(int*型空间,非int型空间)
    for(inti = 0; i < 3; i++)
    {
       p[I] = newint [3];
       p[I][0] = 0;
       p[I][1] = 1;
       p[I][2] = 2;
    }
    for( i = 0; i < 3; i++)
    {
       delete []p[i];
       p[I] = NULL;
    }
    delete []p;
    p=NULL;
int (*l)[2]; //指向一维数组的指针
    l= newint[2][2];
    for(i = 0; i <2;i++)
       for(intj = 0; j <2;j++)
           l[i][j] = i+j;
    delete []l;
用free或delete释放了内存时,如果后面要用到指针后,应立即将指针设置为NULL,防止产生“野指针”。
4.4 重载new和delete
    重载new要和重载delete匹配。
4.4.1 局部重载new和delete
    重载一个与类相关的new和delete函数,只需重载运算符函数成为该类的成员函数。此时重载的new和delete仅用于该特定的类,在其他数据类型上仍然使用原始版本的new和delete。即遇到new和delete时,编译程序首先检查正在使用对象所在的类是否重载了new和delete,如果重载了,则使用这个重载版本;否则,使用全局定义的new和delete。示例如下表左部:
 
classA
{
    intx,y,z;
public:
    A(intx1, inty1);
    ~A(){
    }
    void * operator new(unsignedintsize);
    voidoperator delete(void *p);
};
 
A::A(intx1, inty1)
{
    x=x1; y=y1;
}
void * A::operator new (unsignedintsize)
{
    returnmalloc(size);
    //return (void *)new char[sizeof(A)];
}
voidA::operator delete (void *p)
{
        free(p);
    //delete p;
}
 
voidmain(void)
{
    A *a;
    a = newA(3,10); //调用类A的重载运算符new
    deletea; //调用类A的重载运算符delete
    int *i = newint(100); //调用系统运算符new
    deletei; //调用系统运算符delete
}
classA
{
    intx,y,z;
public:
    A(intx1, inty1);
    ~A(){
    }
};
 
A::A(intx1, inty1)
{
    x=x1; y=y1;
}
void * operator new (unsignedintsize)
{
    returnmalloc(size);
    //return (void *)newchar[size];
}
voidoperator delete (void *p)
{
    free(p);
    //delete p;
}
 
voidmain(void)
{  
    A *a;
    a = newA(3,10); //调用重载运算符new
    deletea; //调用重载运算符delete
    int *i = newint(100); //调用重载运算符new
    deletei; //调用重载运算符delete
}
 
4.4.2 全局重载new和delete
    在任何类外重载new和delete,使它成为全局的。此时,C++中原来的new和delete被忽略,程序中使用重载的new和delete。示例如上表右部:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值