前几天写vector,可把我难倒了。最开始是一个测试用例,没有默认的构造函数,这个时候应该怎样去处理内存的分配。
我想到,既然一个元素的大小,即sizeof()
是固定的,我们就可以先申请这个空间,等到需要使用的时候再赋值。
memcpy()
失败
虽然只学过C++化的简化版C语言,但我想到了malloc()
方法,这就是一个只申请空间,不去填充空间的方法。
这对于传统的数据,就是说所谓的POD(Plain Old Data)是很好的。我的整个实现逻辑也是memcpy()
,这样的处理速度快的多。
但是不是POD的类,占用了堆来存储部分内容,在他的存储空间里只存储了指向堆的指针。所以memcpy()
只执行了浅拷贝,拷贝的实际上是指针,它指向的堆内存储是不变的。当原对象析构释放堆的时候,拷贝对象就被破坏了;被覆盖的对象没有进行析构而是直接被覆盖,内部申请的堆内存就被泄漏。
同样,当被覆盖的地方原本不存在对象,即只分配了内存却没有初始化内存空间时,如果直接调用类的赋值,这个赋值方法是不能检测原来的对象是否正确的。一旦有针对原指向堆内存的指针,现在是随机指针进行的操作,例如直接向动态数组发起memcpy()
,就会出现段错误,或者内存的错误覆盖。
所以,凯撒的归凯撒,经过查阅资料,我找到了下面两个C++的处理方法。
placement new
成功
为什么我最开始不用new
呢?因为new
在调用的时候会自动调用构造函数,而一个用例没有默认构造函数,new就会出错。
怎么解决呢?经过资料的学习,我找到了placement new
这个用法。实际上,new和delete是通过以下的过程实现的。
1 | A* p=new A; B* t=new B[_NUM]; |
过程中的placement new
实际上就是按需调用构造函数,而operator new/delete
则是只申请内存而不初始化,和malloc/free
功能是一致的。好像构造函数是不能够显式调用的,所以placement new
来解决这个问题。