C++细节 C++中的malloc/free ,new/delete

首先,malloc/free 是函数,new/delete是一个操作符

下面看一下malloc,free,realloc函数原型 (引用自C++ reference)

malloc/free ,calloc,realloc

malloc

void* malloc (size_t size);

Allocate memory block

Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.

The content of the newly allocated block of memory is not initialized, remaining with indeterminate values.

If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.

free

void free (void* ptr);

Deallocate memory block

A block of memory previously allocated by a call to malloccalloc or realloc is deallocated, making it available again for further allocations.

If ptr does not point to a block of memory allocated with the above functions, it causes undefined behavior.

If ptr is a null pointer, the function does nothing.

Notice that this function does not change the value of ptr itself, hence it still points to the same (now invalid) location.  

calloc

void* calloc (size_t num, size_t size);

Allocate and zero-initialize array

Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits to zero.

The effective result is the allocation of a zero-initialized memory block of (num*size) bytes.

If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.

realloc

void* realloc (void* ptr, size_t size);

Reallocate memory block

Changes the size of the memory block pointed to by ptr.

The function may move the memory block to a new location (whose address is returned by the function).

The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. If the new size is larger, the value of the newly allocated portion is indeterminate.

In case that ptr is a null pointer, the function behaves like malloc, assigning a new block of size bytes and returning a pointer to its beginning.

calloc是在内存的动态存储区中分配num块长度为"size"字节的连续区域,返回首地址。 

malloc是在内存的动态存储区中分配一块长度为"size"字节的连续区域,返回该区域的首地址。

malloc和free讲述的非常简单和简洁,我就realloc翻译一下,realloc有2个参数,指针ptr,和size

realloc的功能就是修改一个原先已经分配好的空间大小,如果*ptr=NULL,则和malloc一样,是开辟一个size大小的空间

若ptr非空,则分情况讲解,

A第一种情况  realloc(p1,newsize),p1非空,newsize比p1指向的原有空间小,则将尾部空间释放,使空间变为newsize大小

B第二种情况 realloc(p1,newsize),p1非空,newsize比p1指向的原有空间大,但是这一连续空间的尾部之后空间不足以扩容,则另外开辟一块大小为newsize的空间,将原有空间内的内容复制到这个空间,并释放原有空间。并返回一个新地址(指向新开辟的地方)指针。

C第三种情况 realloc(p1,newsize) ,p1非空,newsize比p1指向的原有空间大,尾部空间比较大,则直接在后方进行扩容,指针内容不变。

new/delete

c++继承c语言,按道理来说使用malloc配套的一些函数足以完成任务,为什么添加新的操作符?来完成

C语言有malloc 和free,按道理c++动态开辟使用malloc和free也是可以的

但是,对于内置类型,譬如int,float是可以的

但是对于类则不行

class  A
{
public:
	 A();
	~ A();

private:

};

 A:: A()
{
	 cout << "构造" << endl;
}

 A::~ A()
{
	 cout << "析构" << endl;
}

定义一个类,使用了构造函数则打印 构造,使用析构函数则打印析构

使用我们的测试代码

	A count;
	A  *p1 = new A;
	A  *p2 = (A*)malloc(sizeof(A));
	delete p1;

我们使用了3种 情况

第一种,在栈上创建的count

第二种,new,和delete对应指针p1指向的空间

第三种,malloc在堆上创建的,对应指针p2指向的空间

我在delete后打断点,会出现下面情况

第一个构造是count调用构造函数打印的

第二个是new调用构造函数打印的

第三个析构是delete调用析构函数打印的

由于主函数还没结束,count还处于生命周期,并没有被销毁,故没有调用析构。

那么malloc呢?并没有调用构造,free也不能调用析构函数。

new和malloc还有一个区别,malloc创建失败返回0,new抛出异常,可以使用try catch来协调。

《c++primer》中涉及,标准库定义了operator new和operator delete的8个重载版本

new 和delete的实际过程是

new---》operator new-》malloc-》构造函数,返回ptr指针

delete(ptr)-》析构函数-》operator delete-》free

更简洁的表示,我绘制了下面这个图

调用相应 operator new(size_t) 函数,动态分配内存。调用失败则调用 new_handler() 函数用于处理new失败问题。如果没有设置 new_handler() 函数或者 new_handler() 未能分配足够内存,则抛出异常(一般是这样,书中讲解是有和malloc相同的返回空)。“new运算符”所调用的 operator new(size_t) 函数,按照C++的名字查找规则,首先做依赖于实参的名字查找(即ADL规则),在要申请内存的数据类型T的 内部(成员函数)、数据类型T定义处的命名空间查找;如果没有查找到,则直接调用全局的 ::operator new(size_t) 函数。在分配到的动态内存块上 初始化 相应类型的对象(构造函数)并返回其首地址。如果调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。

 这个具体解释可以参考《c++primer》内存耗尽,称之为定位new

我们需要注意的是operator delete和operator new 是标准库函数,这些函数不仅仅new他们可以调用,普通函数也可以调用的。

这也就解释了引入new和delete的原因

而new[]和delete[]则是针对一组对象,原理和功能是一样的,只需要注意这些函数或者操作符是搭配使用的。

猜你喜欢

转载自blog.csdn.net/weixin_41143631/article/details/81263457