重识new
一、new primernew操作符并不是c++的专属,c运行库有new.h头文件。
C++中的new操作符,众所周知是用来分配动态内存的,而要能达到“动态”这种灵活性的特征,非堆区莫属,因为堆区支持手动分配。如果内存空间不够,new操作符返回空,或抛出异常(下面会讲述3种new操作符,常规new操作符、定位new操作符和禁止抛出异常的new操作符,如果禁止抛异常,那么只好返回空了)
下面代码为MSDN中的,检测new分配是否成功,内存分配失败处理还可以通过_set_new_handler注册分配异常函数结果
// insufficient_memory_conditions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
#define BIG_NUMBER 100000000
int main() {
int *pI = new int;
if( pI == 0x0 ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
对于对象使用new操作符的情况,生成的代码执行的流程一般为:先调用内部合适的new函数,该函数最终调用内存分配API进行堆内存分配,同时初始化一些方便内存管理的结构体和数据。成功分配后,将该地址视为this,如有必要则设置虚表指针,之后调用构造函数对该地址处对象进行构造。构造函数一般也是执行初始化功能而已,修改修改数据啥的。这些都是老生常谈不再赘述。
即使请求的空间是0字节大小,new也会返回不同的地址,也就说总是在不同区域分配。这里注意和空类的区别,空类的大小是1,传给new函数(该函数在之后给出)之后,new函数接受到的参数只会>=1,而对于特殊情况:char* pch=new char;new函数接受的参数确实是0,不过分配的空间并不是0字节,因为存在内存管理相关的结构体也会占用内存。
new操作符有2种作用域,一种是全局new,一种是类作用域new。用户在自定义类中可以重载自定义new函数。代码如下:
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// 对于Blanks对象,全局new操作符已被替换,因此下面的代码将分配sizeof(Blanks)大小的空间并把数据赋值为0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
二、new primer plus
new和delete操作符是通过一种称为自由存储区的内存池分配内存的,而new和delete操作符本身在编译时会由编译器选择合适的new函数和delete函数进行实现。
C运行库的new函数会在失败时抛出std::bad_alloc异常,如果要使用不抛出异常的new版本,则需要链接nothrownew.obj,然而一旦链接了该文件,标准C++库中的new就不起作用了
new有2种语法形式
[::] new new-type-name
[::] new ( type-name )
2种new函数原型为:
void* operator new( std::size_t _Count ) throw(bad_alloc);
void* operator new( std::size_t _Count, const std::nothrow_t& ) throw( );
void* operator new( std::size_t _Count, void* _Ptr ) throw( );
void *operator new[]( std::size_t _Count ) throw(std::bad_alloc);
void *operator new[]( std::size_t _Count, const std::nothrow_t& ) throw( );
void *operator new[]( std::size_t _Count, void* _Ptr ) throw( );
其用法如下:
// new_op_new.cpp
// compile with: /EHsc
#include<new>
#include<iostream>
using namespace std;
class MyClass
{
public:
MyClass( )
{
cout << "Construction MyClass." << this << endl;
};
~MyClass( )
{
imember = 0; cout << "Destructing MyClass." << this << endl;
};
int imember;
};
int main( )
{
// The first form of new delete
MyClass* fPtr = new MyClass;
delete fPtr;
// The second form of new delete
MyClass* fPtr2 = new( nothrow ) MyClass;
delete fPtr2;
// The third form of new delete
char x;
MyClass* fPtr3 = new( &x ) MyClass;
fPtr3 -> ~MyClass();
cout << "The address of x is : " << ( void* )&x << endl;
}
Construction MyClass.000B3F30
Destructing MyClass.000B3F30
Construction MyClass.000B3F30
Destructing MyClass.000B3F30
Construction MyClass.0023FC60
Destructing MyClass.0023FC60
The address of x is : 0023FC60
// new_op_alloc.cpp
// compile with: /EHsc
#include <new>
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass() {
cout << "Construction MyClass." << this << endl;
};
~MyClass() {
imember = 0; cout << "Destructing MyClass." << this << endl;
};
int imember;
};
int main() {
// The first form of new delete
MyClass* fPtr = new MyClass;
delete[ ] fPtr;
// The second form of new delete
char x;
MyClass* fPtr2 = new( &x ) MyClass;
fPtr2.~MyClass();
fPtr2.~MyClass();
cout << "The address of x is : " << ( void* )&x << endl;
// The third form of new delete
MyClass* fPtr3 = new( nothrow ) MyClass;
delete[ ] fPtr3;
}
Construction MyClass.00311AEC
Construction MyClass.00311AF0
Destructing MyClass.00311AF0
Destructing MyClass.00311AEC
Construction MyClass.0012FED4
Construction MyClass.0012FED8
Destructing MyClass.0012FED8
Destructing MyClass.0012FED4
The address of x is : 0012FED0
Construction MyClass.00311AEC
Construction MyClass.00311AF0
Destructing MyClass.00311AF0
Destructing MyClass.00311AEC
他们是怎么实现的呢?请听下回分解 哈哈 卖关子
页:
[1]