new实际上执行了什么操作,可能在什么步骤出现异常?
当我们使用关键字new在堆上动态创建一个对象时,它实际上做了三件事:
1)获得一块内存空间;
2)调用构造函数;
3)返回正确的指针。
当然,如果我们创建的是简单类型的变量,那么第二步会被省略。
申请内存可能new失败会抛出bad_alloc异常。
new 与malloc的区别
0、申请地区域: malloc在堆上分配的内存块,使用free释放内存,而new所申请的内存则是在自由存储区上,使用delete来释放。
1、调用:new在申请空间的时候会调用构造函数,malloc不会调用
2、申请失败返回:new在申请空间失败后返回的是错误码bad_alloc,malloc在申请空间失败后会返回NULL
3、属性上:new/delete是C++关键字需要编译器支持,maollc是库函数,需要添加头文件
4、参数:new在申请内存分配时不需要指定内存块大小,编译器会更具类型计算出大小,malloc需要显示的指定所需内存的大小
5、成功返回类型:new操作符申请内存成功时,返回的是对象类型的指针,类型严格与对象匹配,无需进行类型转换,因此new是类型安全性操作符。malloc申请内存成功则返回void*,需要强制类型转换为我们所需的类型
自由存储区与堆
从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。
基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。
我们所需要记住的就是:
堆是操作系统维护的一块内存,而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。堆与自由存储区并不等价。
在Herb Sutter的《exceptional C++》中,明确指出了free store(自由存储区) 与 heap(堆) 是有区别的。关于自由存储区与堆是否等价的问题讨论,大概就是从这里开始的:
Free Store
The free store is one of the two dynamic memory areas, allocated/freed by new/delete. Object lifetime can be less than the time the storage is allocated; that is, free store objects can have memory allocated without being immediately initialized, and can be destroyed without the memory being immediately deallocated. During the period when the storage is allocated but outside the object's lifetime, the storage may be accessed and manipulated through a void* but none of the proto-object's nonstatic members or member functions may be accessed, have their addresses taken, or be otherwise manipulated.
Heap
The heap is the other dynamic memory area, allocated/freed by malloc/free and their variants. Note that while the default global new and delete might be implemented in terms of malloc and free by a particular compiler, the heap is not the same as free store and memory allocated in one area cannot be safely deallocated in the other. Memory allocated from the heap can be used for objects of class type by placement-new construction and explicit destruction. If so used, the notes about free store object lifetime apply similarly here.
来源:http://www.gotw.ca/gotw/009.htm
作者指出,之所以把堆与自由存储区要分开来,是因为在C++标准草案中关于这两种区域是否有联系的问题一直很谨慎地没有给予详细说明,而且特定情况下new和delete是按照malloc和free来实现,或者说是放过来malloc和free是按照new和delete来实现的也没有定论。这两种内存区域的运作方式不同、访问方式不同,所以应该被当成不一样的东西来使用。
除此之外
1、在C++中如何限制一个类对象只在堆上分配?
只在堆上意味着只可以通过new来申请内存。
class heapOnly
{
private:
heapOnly() { }
~heapOnly() { }
};
将构造函数设为私有,因此,当你生成heapOnly对象时会自动调用构造函数,这时编译器也会报错。
仿照设计模式中的单实例模式,这里采用单实例模式方式来说明。将类的构造函数属性置为private,同时提供static成员函数getInstance,在函数中new一个新对象,然后返回对象指针或者引用。这样实现的类可以保证只可以在堆上分配对象。
2、在C++中如何限制一个类对象只在栈上分配?
只在栈上 :意味着不可以通过new申请内存
class StackOnly
{
private:
void * operator new(size_t Size) { }
};
它利用了c++的重载机制+访问控制机制。重载了new运算符,并设为私有,因此,当用 new stackOnly;时编译器就会报错。
重载类的new操作符,使重载后的new操作符的功能为空。这样就使外层程序无法在堆上分配对象,只可以在栈上分配。
4、怎么突破private的限制访问变量?
因为编译器不会对指针做private检查,通过构造指向一个对象的指针,然后调正偏移量来非法访问。
这就是C++强大的地方之一。
网友评论