c/c++部分知识总结

c/c++部分知识总结

1、C语言中malloc、calloc、realloc的不同


(1) malloc分配指定字节数的存储区。此存储区中的初始值不确定 
(2) calloc为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位(bit)都初始化为0 
(3) realloc 更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定 
.分配函数时再分配 realloc()使我们可以增、减以前分配区的长度(最常见的用法是增加该区)。如果先分配一个可容纳长度为512的数组的空间,并在运行时填充它,但又发现空间不够,则可调用realloc扩充该存储空间。如果在该存储区后有足够的空间可供扩充,则可在原存储区位置上向高地址方向扩充,并返回传送给它的同样的指针值。如果在原存储区后没有足够的空间,则realloc分配另一个足够大的存储区,将现存的5 1 2个元素数组的内容复制到新分配的存储区。因为这种存储区可能会移动位置,所以不应当使用任何指针指在该区中。 
注意,realloc的最后一个参数是存储区的newsize(新长度),不是新、旧长度之差。作为一个特例,若ptr是一个空指针,则realloc的功能与malloc相同,用于分配一个指定长度newsize的存储区。 

2、常见的内存泄露,C/C++如何进行内存泄露检测?


常见的内存泄露问题包括 : 
堆内存泄露和系统资源泄露 
简单的潜在堆内存丢失和缓冲区覆盖 
来自资源错误管理的潜在堆内存丢失 
未初始化的指针 
两个错误的内存释放 
悬空指针 
(1)malloc/free 和 new/delete 没有配套使用,导致了内存泄露。 
内存泄露检测 
(2)配套使用 
malloc\realloc ------ free 
new \new[] ---------- delete \delete[] 

3、malloc/free和 new/delete的区别
区别:mallocfree是c语言的申请内存的方式,c语言中没有构造这一概念,malloc只是申请空间,并不会初始化,当申请空间失败后返回0,而且free仅仅释放工作;
new int(内置类型) 不会调用构造函数,只有new +自定义类型才会调用构造函数。
New []一个类的时候,当我们自己定义一个析构函数时会在1前面多开辟4个字节,用来决定析构多少次,当使用系统的析构函数的时候,不会多开辟4个字节。
New申请空间的底层代码实现也是调用malloc来完成。不过对malloc进行了封装,c语言中当malloc申请空间失败后会返回0,c++中申请失败会抛异常,因此在c++中new一块空间不用检测是否申请到空间,直接使用就可以了。

``
底层实现如下:
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0) //当申请空间失败抛异常
if (_callnewh(size) == 0)
{ // report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
4、new/new[]/delete/delete[]的执行过程
New 类-> operator new -> maloloc -> 构造函数
Delete -> operator delete -> free ->析构函数->free

New[] +类 -> operator new[]->operator new -> malloc ->构造函数
Delete[] ->operator delete[]->operator delete->析构函数->free
5、熟悉–>operator new 和定位new表达式


定位new表达式的用途,当一块空间使用了malloc 申请好了之后,但是malloc中没有构造函数,但是c++中需要调用构造函数证明一个类的生成,这时候就可以使用定位new表达式 
Char* tmp = (char*)malloc(10) 
New(tmp)AA //AA是一个类 

6、一个类如何只在堆上创建对象

``` 
在C++中,类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* ptr=new A;这两种方式是有区别的。 
1、静态建立类对象:是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。 
2、动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。

7、一个类如何只在栈上创建对象 

``` 
编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下: 
class A 

public: 
A(){} 
void destory(){delete this;} 
private: 
~A(){} 
};

只能在栈上分配类对象 
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。虽然你不能影响new operator的能力(因为那是C++语言内建的),但是你可以利用一个事实:new operator 总是先调用 operator new,而后者我们是可以自行声明重写的。因此,将operator new()设为私有即可禁止对象被new在堆上。代码如下: 
class A 

private: 
void* operator new(size_t t){} // 注意函数的第一个参数和返回值都是固定的 
void operator delete(void* ptr){} // 重载了new就需要重载delete 
public: 
A(){} 
~A(){} 
}; 
``

8、扩展:探索malloc的实现方式

```
关于VirtualAlloc函数:
其实在windows中在对管理器上提供了几个函数用来创建、分配、释放和销毁堆空间(我们申请的空间是在堆上的),从而实现了分配算法。

HeapCreat:创建一个堆
HeapAlloc:在堆里分配空间
HeapFree:释放分配的内存
HeapDestroy:销毁一个堆

这里的HeapCreat便是创建一个堆空间它申请内存空间便是通过VirtualAlloc函数来实现的。HeapAlloc函数是在堆空间里面给用户分配小的内存空间,如果内存不足它也能通过VirtualAlloc向系统申请更多的内存。

Malloc函数:
malloc函数其实是上面几个Heap操作函数的包装。
堆空间是程序申请出来的一大块空间,当我们用malloc函数申请空间的时候大小是不确定的,有可能是很小的一块空间也有可能是很大的一块空间,所以对堆空间也是需要一定的方法进行管理的,当你需要申请空间的时候按照你申请的大小以一定方法分配给你。
这就是分配算法,分配算法有很多种,对于不同的场合是有不同的分配算法的。在这里只简单的描述一下几种简单的算法。

Malloc底层实现:http://www.cnblogs.com/MrListening/p/5538665.html

1. 空闲链表
2. 位图
位图有它的优点:
比空闲链表更加稳定,因为可以对数组进行备份,而且就算某个块损坏,也不会影响整个位图其他的块空间。
速度比较快还容易管理。
同时也有它的缺点:
也容易造成块的浪费,因为毕竟它是整数倍的分配。
当堆比较大的时候,可能这个位图会很大,数组很庞大,可能效率也并不像想象那么快。
3. 对象池
还有一种方法是对象池,也是把堆空间分成了大小相等的一些块,它是认为某些场合每次分配的空间都相等,所以每次就直接返回一个块的大小,它的管理方法可以是链表也可以是位图。因为不用每次查找合适的大小的内存返回,所以效率很高。
其实在实际的应用中,堆的分配算法有很多,上面的三种只是其中简单的几种,而且在实际分配中它是根据应用场景可能对应不同的分配算法,也可能是多种算法的结合。只有这样才会达到高效的这么一个原则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值