C++--new和delete

1.定义

  • 在c语言中,关于动态内存分配的方式有malloc,calloc,realloc,释放内存的话有free等方式。而在c++中,提供了一种新的更加完善和方便的动态内存的分配和释放的方式,即new和delete。
  • new的格式:
  1. 指针类型  指针变量名  = new  类型
  2. 指针类型  指针变量名  = new  类型(初始值)
  3.  指针类型  指针变量名  = new  类型[元素个数]
  • delete的格式:
  1. delete  指针变量名
  2. delete[]  指针变量名

2.new和delete对内置类型的操作

//申请空间
int* ptr = new int;

//申请空间并初始化
int* ptr2 = new int(1);
	
//申请连续的空间,空间大小为4*10=40
int* arr = new int[10];//c++98不允许连续空间初始化


//释放单个空间
delete ptr;
delete ptr2;

//释放连续的多个空间
delete[] arr;

3.new和delete对自定义类型的操作

class A
{
public:
     A(int a=10)
     :_a(a)
     {
         cout<<"A()的初始化:"<<_a<<endl;
     }

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

private:
     int _a;
};


int main()
{
    A* pa1=new A;
    delete pa1;
    return 0;
}

(我们可以看到,new和delete会分别调用构造函数和析构函数,而malloc和free则不会)

  • 如果没有默认构造函数,我们必须在new一个对象时后面要加小括号给予初始值进行初始化。没有默认构造函数,我们也不能申请连续的多个空间。
class A
{
public:
     A(int a)//不是默认构造函数
     :_a(a)
     {
         cout<<"A()的初始化:"<<_a<<endl;
     }

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

private:
     int _a;
};


int main()
{
    //因为没有默认构造函数,所以报错
    A* pa1=new A;
    delete pa1;

    //可以运行
    A* pa2=new A(10);
    delete pa2;
    return 0;
}
  • 如果类中有多个成员变量,也只要把我们想要赋给对象的值放在小括号里,用逗号隔开。
class A
{
public:
     A(int a=10,int b=20,int c=30)//不是默认构造函数
     :_a(a)
     ,_b(b)
     ,_c(c)
     {}


private:
     int _a;
     int _b;
     int _c;
};


int main()
{
   //使用传入的值
	A* pa1 = new A(10, 20, 30);
	delete pa1;

	//使用缺省参数
	A* pa2 = new A;
	delete pa2;

	//全部使用缺省参数
	A* arr = new A[10];
	delete[] arr;
    return 0;
}
  • 注意:new,delete,new[],delete[],malloc和free建议成对使用。
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}

	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

int main()
{
	
	A* p2 = new A[10];  //会报错,size的大小会是40或者44
	free(p2);
	return 0;
}

(当类型是内置类型的时候,相互使用并不会有影响,但是是用户自定义类型的时候,就会报错。如上图所示,2ch是44,为什么是44字节呢?因为多出来的4个字节是用来存总字节数目的,如果你用free来释放,就会报错)

4.operator new和operator delete函数

  • new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是 系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。
 /*operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。*/

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
         // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
         static const std::bad_alloc nomem;
         _RAISE(nomem);
     }
     return (p);
}

 /*operator delete: 该函数最终是通过free来释放空间的*/
 
void operator delete(void *pUserData)
{
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
     return;
     _mlock(_HEAP_LOCK);  /* block other threads */
     __TRY
     /* get a pointer to memory block header */
     pHead = pHdr(pUserData);
     /* verify block type */
     _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
     _free_dbg( pUserData, pHead->nBlockUse );
     __FINALLY
     _munlock(_HEAP_LOCK);  /* release other threads */
     __END_TRY_FINALLY
     return;
}
 /*
 free的实现
*/
 #define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

(通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果 malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施 就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的)

  • new,operator new,malloc和delete,operator delete,free三者的关系:
  1. operator new = malloc + 失败抛异常
  2. new = operator new + 调用构造函数
  3. new = malloc + 失败抛异常 + 调用构造函数
  4. operator delete = free
  5. delete = operator + 调用析构函数
  6. delete = free + 调用析构函数

4.1new和delete的原理实现

  • new的原理
  1.  调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造
  • delete的原理
  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2.  调用operator delete函数释放对象的空间
  • new T[N]的原理
  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对 象空间的申请
  2. 在申请的空间上执行N次构造函数
  • delete[]的原理
  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释 放空间

5.定位new(placement-new)

  • 定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
  • 使用格式:
  1. new (place_address) type
  2. new (place_address) type(initializer-list)    (place_address必须是一个指针,initializer-list是类型的初始化列表)

5.1使用场景

  • 在工作中,我们会有多个类,也会有多个对象,平凡的去申请空间会增加系统的开销,C++引入了内存池去减小系统开销,且可以提高效率。内存池的工作原理是先向系统一次性申请比较大的空间,当我们每次去申请空间时就直接使用内存池里的空间,而省略了申请和释放的两个开销动作,也减少了系统内存碎片,从而提高了开发效率。

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}

	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

int main()
{
	A* p1 = new A;//开辟空间
	//或者
	A* p1 = (A*)operator new(sizeof(A));//用operator new的方法拟实现new来开辟空间
	new(p1)A;  // 对已有空间,显示调用构造
	new(p1)A(10);  // 对已有空间,显示调用构造

	A* p1 = pool.alloc(sizeof(A));
	new(p1)A(10);  // 对已有空间,显示调用构造
	
	// delete p1
	p1->~A();
	operator delete(p1);
	
	// new []用定位new的拟实现
	A* p2 = (A*)operator new[](sizeof(A)*10);//用operator new[]创造新空间
	new(p2)A[10]{1,2,3,4};  // 对已有空间,显示调用构造
	for (int i = 0; i < 10; ++i)
		new(p2 + i)A(i);

	// delete[]的拟实现
	for (int i = 0; i < 10; i++)
	{
		(p2 + i)->~A();
	}
	operator delete[](p2);

	return 0;
}

 6.malloc/free和new/delete的区别

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时需要手动计算空间大小并传递,new不需要
  4. malloc的返回值为void*,使用时必须强转来接收,new不需要
  5. malloc申请失败时返回NULL,new申请失败会抛异常
  6. 申请自定义类型的对象时,malloc/free不会调用构造函数和析构函数,而new会申请空间后调用构造函数,delete会调用析构函数后再释放空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值