作者tomap41017 (绝梦)
看板EE_DSnP
标题Re: [问题] delete和delete[]
时间Wed Oct 13 01:06:12 2010
刚刚用open office编辑结果它当了,害我要重打,要养成存档的好习惯。
老师下课说在版上去年这时候应该有文章,不过我找了好久都找不到阿,
後来翻阅一下手边的工具书,觉的应该是POD造成的问题(Plain Old Data)。
写个小程式测试一下:
#include <iostream>
#include <vector>
using namespace std;
class POD {
int i;
};
class NonPOD {
double i;
~NonPOD() {
}
};
template<class T>
void test() {
typedef T* Pointer;
Pointer p = new T[10];
void *v = reinterpret_cast<void*> (p);
size_t* size = reinterpret_cast<size_t*> (v - sizeof(size_t));
cout << *size << endl;
}
int main() {
test<POD> ();
test<int> ();
test<std::vector<int> > ();
test<NonPOD> ();
}
此程式在我的电脑编译(g++4.4.3)执行结果为:
49
49
10
10
什麽是POD呢?简单说就是class没有定义constructor/copy constructor/assignment
operator/destructor这四种,完全靠compiler generated版本(这个版本也称作
trivial – constructor/....),那是POD跟这个array删除有什麽关联阿?
这可以从这次作业HW1.2.2这题看起,在Vector中,我们要初始化_data这个pointer,
我们会写_data = new unsigned[size]; 如果你没有用一个回圈去初始化每个值,当直接
读取
时,有时後会得到垃圾值。若我们想要让他们都能够初始化成unsigned的预设值呢?
可以写:
_data = new unsigned[size]();
我们再看到Matrix,在constructor内要初始化_data,不过这时候问题来了:
_data = new Vector[numRows]; 会呼叫Vector的哪一个constructor阿?
如果你有用_data[1].size()去读出它的值,会发现是0,也就是
Vector::Vector(unsigned = 0);被呼叫了。
我们可以看到,在初始化一个阵列时我们只能(implicitly or explicitly)呼叫其
default
constructor,我们从int的例子可以发现,不加上()时,constructor不会被呼叫,
而不会把每个元素的初始值设为零;而在Vector的例子,编译器有看到default
constructor,因此判定它不是POD,implicitly呼叫每个元素的default ctor。
(当你把在Vector::Vector的预设参数拿掉时,编译器就会唉啦:你没给我一个
default constructor我怎麽建构阿?而且你已经写了constructor了,
我更不可能帮你写一个阿!!)
这就是编译器对待不同类型的type会有不同的处理方式!!
如果你的class没有写任何constructor,编译器就会帮你写一份,但那份
里面什麽都不做。
(对copy ctor跟assignment operator而言则是 memner wise assignment,
所以你呼叫Vector a(b);//利用另一个Vector b来建构a
是会通过编译的,只不过在a,b被摧毁时delete 2 _data指的记忆体。
)
好,重点来了,对於destructor而言,编译器帮你写得那份,有要作什麽用吗?
答案是:没有,而且对於内建型别(int double)而言也是一样,
所以在上面的测试程式中,我们看到POD, int得到的是相似结果,
而std::vector<int>与NonPOD得到的是10的结果,也就是阵列大小。
编译器知道阵列大小要作什麽用阿?答案就是在摧毁阵列时明白呼叫其destructor罗!
for(int I = 0; I < size; ++i){
_data[I].~Vector();
}
而没有定义destructor的POD,只要把记忆体删除,这个物件也就掰了~~
所以int[]与POD[]都不需要存阵列大小。
※ 引述《puerpuella (柏亨)》之铭言:
我在写作业的时候对delete产生了一点疑惑...
我本来以为delete是删除一个object用的,而delete[]是删除多个用的
但是我在main()中宣告
double* d = new double[1];
之後不管我写delete d; 或delete []d; 执行都会成功
而且就算我是宣告double* d = new double[0]; 时也可以
可是我写了一个class叫做C,在main()中
C* c = new C[1];
delete c;
这样执行就不过了,一定要用delete[]才OK
是因为宣告时如果有用[ ],delete的时候就要加吗?
可是在double的时候好像不用加[]也行?
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.112.245.114
1F:推 ric2k1:new [] 的变数用 delete 只会 delete 其中的一个,其他的 10/11 22:20
2F:推 ric2k1:会变成 memory leak. 照理来说不会马上 crash,如果会crash 10/11 22:20
3F:→ ric2k1:应该是其他原因 10/11 22:21
4F:推 ric2k1:简单的说: 用 new [] 就要用 delete [], 反之用 new 则要用 10/11 22:22
5F:→ ric2k1:delete. 10/11 22:22
6F:→ ric2k1:明天上课会再说明一下。 10/11 22:23
7F:→ puerpuella:谢谢教授!!我後来又试了一下如果我C里面没写destructor 10/11 22:34
8F:→ puerpuella:就不会有事,可是一加上~C()就挂了.. 10/11 22:34
9F:推 ric2k1:这个跟去年的 HW1.2 P3 有关... 我明天来一起讲解一下! 10/11 23:04
10F:推 johnjohnlin:要作 deep copy 吧?我之前也这样 10/12 15:50
简单讲应该也是deep copy啦XDDDDDDDDd
附注一下:
Exceptional C++ (我是看国际中文版,英文版应该是3e?)
Item 36:有写到
一般的compiler在destructor通常的实做方式为,
会在dtor函式码尾端有一个不可见旗标,
如果此变数是一个auto物件(非new出来的)则此旗标为false
若是一个dynamic物件,则此旗标为true
这个旗标代表的是『当这物件被摧毁时,我该删除它吗?』
如果为true,则在尾端呼叫正确(就是该class)的operator delete()
(忘了说,class defined operator delete隐喻为static)
若class B有virtual dtor,且也有(static) B::operator delete(void*);
class D为其derived class,但只定义(static) D::operator delete(void*);
则
D* ptr = new D;
delete ptr;//唤起D::operator delete(void*)
但
B* ptr2 = new D;
delete ptr2;//因为有virtual dtor,唤起~D(),
~D()内则一样唤起D::operator delete(void*);
所以compiler其实有帮我们作一些事情的(在trivial内)。
※ 编辑: tomap41017 来自: 140.112.244.171 (10/13 01:17)
11F:推 ric2k1:推一个!! 抱歉,我说的文章是 #2451 10/13 01:11
12F:→ tomap41017:突然觉的我写得落落长 囧 10/13 01:19
13F:推 ric2k1:不会啊! 讲得很清楚!! 感谢 10/13 01:41
14F:推 aitjcize:大推! 10/14 00:49