C/C++学习----第四章 内存分配及其管理

 
    在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 = new int [ 20 ];
<2> new()可以将创建的对象初始化。
int * p = new int(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>在类中增加不带参数的构造函数来初始化(如下表左)。
 
class point {
public :
    int x , y ;
    point ( int ox , int oy );
point ();
};
point::point ( int ox , int oy ){
       x = ox ;
       y = oy ;
    }
point::point (){
       x = 10 ;
       y = 10 ;
}
void main ()
{
    point * p1 = new point ( 3 , 3 ); //声明对象指针,创建对象并调用带参数的构造函数,初始化对象
    point * p2 = new point [ 5 ]; //声明对象数组指针,创建对象并调用不带参数的构造函数,初始化对象
        delete p1;
    delete [] p2 ;
}
Class point {
Public :
    int x , y ;
void setPoint ( int ox, int oy);
};
void point :: setPoint ( int ox, int oy){
       x = ox;
       y = oy;
    }
 
void main ()
{
    point * p2 = new point [ 5 ]; //声明对象数组指针,创建对象
    for ( int i = 0 ; i < 5 ; i ++)
       p2[ i ].setPoint( 10 , 10 ); //调用 setPoint函数对成员变量促使化
delete [] p2 ;
}
 
 
       
类的每个指针成员要么指向有效的内存,要么就指向空,在析构函数里可简单地 delete,而不用担心该指针是不是被new过。
使用 new()创建多维数组时,必须提供各维的大小。如:
    int (* l )[ 2 ];
l = new int [ 2 ][2]; //ok
l = new int [ 2 ][]; //error
l = new int [][ 2 ]; //error
创建两维数组,举例
int ** p = new int *[ 3 ]; //首先分配指针数组中各个指针(p[0],p[1],p[2])的空间(int*型空间,非int型空间)
    for ( int i = 0 ; i < 3 ; i ++)
    {
       p [ I ] = new int [ 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 = new int [ 2 ][ 2 ];
    for ( i = 0 ; i < 2 ; i ++)
       for ( int j = 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。示例如下表左部:
 
class A
{
    int x , y , z ;
public :
    A ( int x1 , int y1 );
    ~ A (){
    }
    void * operator new( unsigned int size );
    void operator delete( void * p );
};
 
A :: A ( int x1 , int y1 )
{
    x = x1 ; y = y1 ;
}
void * A :: operator new ( unsigned int size )
{
    return malloc ( size );
    //return (void *)new char[sizeof(A)];
}
void A :: operator delete ( void * p )
{
        free ( p );
    //delete p;
}
 
void main ( void )
{
    A * a ;
    a = new A ( 3 , 10 ); //调用类A的重载运算符new
    delete a ; //调用类A的重载运算符delete
    int * i = new int ( 100 ); //调用系统运算符new
    delete i ; //调用系统运算符delete
}
class A
{
    int x , y , z ;
public :
    A ( int x1 , int y1 );
    ~ A (){
    }
};
 
A :: A ( int x1 , int y1 )
{
    x = x1 ; y = y1 ;
}
void * operator new ( unsigned int size )
{
    return malloc ( size );
    //ret urn ( void *) new char [size];
}
void operator delete ( void * p )
{
    free ( p );
    //delete p;
}
 
void main ( void )
{  
    A * a ;
    a = new A ( 3 , 10 ); //调用重载运算符new
    delete a ; //调用重载运算符delete
    int * i = new int ( 100 ); //调用重载运算符new
    delete i ; //调用重载运算符delete
}
 
4.4.2 全局重载new和delete
    在任何类外重载new和delete,使它成为全局的。此时,C++中原来的new和delete被忽略,程序中使用重载的new和delete。示例如上表右部:
 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pony12

助力1000篇OpenDDS文

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值