Toán tử new và delete – Tài liệu text

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.23 MB, 390 trang )

Hình 2.6: Kết quả của ví dụ 2.5 Tốn tử định phạm vi còn được dùng trong các định nghĩa hàm của các phương thức trong các lớp, để
khai báo lớp chủ của các phương thức đang được định nghĩa đó. Tốn tử định phạm vi còn có thể được dùng để phân biệt các thành phần trùng tên của các lớp cơ sở khác nhau.

2.2.9 Toán tử new và delete

Trong các chương trình C, tất cả các cấp phát động bộ nhớ đều được xử lý thông qua các hàm thư viện như malloc, calloc và free. C++ định nghĩa một phương thức mới để thực hiện việc cấp phát
động bộ nhớ bằng cách dùng hai toán tử new và delete. Sử dụng hai toán tử này sẽ linh hoạt hơn rất nhiều so với các hàm thư viện của C. Đoạn chương trình sau dùng để cấp phát vùng nhớ động theo lối
cổ điển của C.
int P; P = mallocsizeofint;
if P==NULL printfKhong con du bo nho de cap phat\\n;
else {
P = 290; printfd\\n, P;
freeP; }
Trong C++, chúng ta có thể viết lại đoạn chương trình trên như sau: int P;
P = new int; if P==NULL
coutKhong con du bo nho de cap phat\\n; else
15
{ P = 290;
coutP\\n; delete P;
}
Chúng ta nhận thấy rằng, cách viết của C++ sáng sủa và dễ sử dụng hơn nhiều. Toán tử new thay thế cho hàm malloc hay calloc của C có cú pháp như sau :
new type_name new type_name
new type_name initializer new type_name initializer
Trong đó : type_name: Mơ tả kiểu dữ liệu được cấp phát. Nếu kiểu dữ liệu
mô tả phức tạp, nó có thể được đặt bên trong các dấu ngoặc.
initializer: Giá trị khởi động của vùng nhớ được cấp phát.
Nếu tốn tử new cấp phát khơng thành cơng thì nó sẽ trả về giá trị NULL. Còn tốn tử delete thay thế hàm free của C, nó có cú pháp như sau :
delete pointer delete [] pointer
Chúng ta có thể vừa cấp phát vừa khởi động như sau : int P;
P = new int100; if P=NULL
{ coutP\\n;
delete P; 16
} else
coutKhong con du bo nho de cap phat\\n; Để cấp phát một mảng, chúng ta làm như sau :
int P; P = new int[10]; Cấp phát mảng 10 số nguyên
if P=NULL {
forint I = 0;I10;++ P[I]= I;
forI = 0;I10;++ coutP[I]\\n;
delete []P; }
else coutKhong con du bo nho de cap phat\\n;
Chú ý: Đối với việc cấp phát mảng chúng ta không thể vừa cấp phát vừa khởi động giá trị cho chúng,
chẳng hạn đoạn chương trình sau là sai : int P;
P = new int[10]3; Sai Ví dụ 2.6:
Chương trình tạo một mảng động, khởi động mảng này với các giá trị ngẫu nhiên và sắp xếp chúng.
CT2_6.CPP
1: include iostream.h 2: include time.h
3: include stdlib.h 4: int main
17
5: { 6: int N;
7: coutNhap vao so phan tu cua mang:; 8: cinN;
9: int P=new int[N]; 10: if P==NULL
11: { 12: coutKhong con bo nho de cap phat\\n;
13: return 1; 14: }
15: srandunsignedtimeNULL; 16: forint I=0;IN;++I
17: P[I]=rand100; Tạo các số ngẫu nhiên từ 0 đến 99 18: coutMang truoc khi sap xep\\n;
19: forI=0;IN;++I 20: coutP[I] ;
21: forI=0;IN-1;++I 22: forint J=I+1;JN;++J
23: if P[I]P[J] 24: {
25: int Temp=P[I]; 26: P[I]=P[J];
27: P[J]=Temp; 28: }
29: cout\\nMang sau khi sap xep\\n; 30: forI=0;IN;++I
31: coutP[I] ;
18
32: delete []P; 33: return 0;
34: }
Chúng ta chạy ví dụ 2.6
, kết quả ở hình 2.7
Hình 2.7: Kết quả của ví dụ 2.6 Ví dụ 2.7:
Chương trình cộng hai ma trận trong đó mỗi ma trận được cấp phát động.Chúng ta có thể xem mảng hai chiều như mảng một chiều như hình 2.8
Hình 2.8: Mảng hai chiều có thể xem như mảng một chiều. Gọi X là mảng hai chiều có kích thước m dòng và n cột.A là mảng một chiều tương ứng.Nếu X[i][j]
chính là A[k] thì k = in + j Chúng ta có chương trình như sau :
CT2_7.CPP
1: include iostream.h
19
2: include conio.h 3: prototype
4: void AddMatrixint A,int B,intC,int M,int N; 5: int AllocMatrixint A,int M,int N;
6: void FreeMatrixint A; 7: void InputMatrixint A,int M,int N,char Symbol;
8: void DisplayMatrixint A,int M,int N; 9:
10: int main 11: {
12: int M,N; 13: int A = NULL,B = NULL,C = NULL;
14: 15: clrscr;
16: coutNhap so dong cua ma tran:; 17: cinM;
18: coutNhap so cot cua ma tran:; 19: cinN;
20: Cấp phát vùng nhớ cho ma trận A 21: if AllocMatrixA,M,N
22: { endl: Xuất ra kí tự xuống dòng ‘\\n’ 23: coutKhong con du bo nhoendl;
24: return 1; 25: }
26: Cấp phát vùng nhớ cho ma trận B 27: if AllocMatrixB,M,N
28: {
20
29: coutKhong con du bo nhoendl; 30: FreeMatrixA;Giải phóng vùng nhớ A
31: return 1; 32: }
33: Cấp phát vùng nhớ cho ma trận C 34: if AllocMatrixC,M,N
35: { 36: coutKhong con du bo nhoendl;
37: FreeMatrixA;Giải phóng vùng nhớ A 38: FreeMatrixB;Giải phóng vùng nhớ B
39: return 1; 40: }
41: coutNhap ma tran thu 1endl; 42: InputMatrixA,M,N,A;
43: coutNhap ma tran thu 2endl; 44: InputMatrixB,M,N,B;
45: clrscr; 46: coutMa tran thu 1endl;
47: DisplayMatrixA,M,N; 48: coutMa tran thu 2endl;
49: DisplayMatrixB,M,N; 50: AddMatrixA,B,C,M,N;
51: coutTong hai ma tranendl; 52: DisplayMatrixC,M,N;
53: FreeMatrixA;Giải phóng vùng nhớ A 54: FreeMatrixB;Giải phóng vùng nhớ B
55: FreeMatrixC;Giải phóng vùng nhớ C
21
56: return 0; 57: }
68: Cộng hai ma trận 69: void AddMatrixint A,int B,intC,int M,int N
70: { 71: forint I=0;IMN;++I
72: C[I] = A[I] + B[I]; 73: }
74: Cấp phát vùng nhớ cho ma trận 75: int AllocMatrixint A,int M,int N
76: { 77: A = new int [MN];
78: if A == NULL 79: return 0;
80: return 1; 81: }
82: Giải phóng vùng nhớ 83: void FreeMatrixint A
84: { 85: if A=NULL
86: delete [] A; 87: }
88: Nhập các giá trị của ma trận 89: void InputMatrixint A,int M,int N,char Symbol
90: { 91: forint I=0;IM;++I
92: forint J=0;JN;++J
22
93 { 94: coutSymbol[I][J]=;
95: cinA[IN+J]; 96: }
97: } 100: Hiển thị ma trận
101: void DisplayMatrixint A,int M,int N 102: {
103: forint I=0;IM;++I 104: {
105: forint J=0;JN;++J 106: {
107: out.width7;Hien thi canh le phai voi chieu dai 7 ky tu
108: coutA[IN+J]; 109: }
110: coutendl; 111: }
112: }
Chúng ta chạy ví du 2.7
, kết quả ở hình 2.9
23
Hình 2.9: Kết quả của ví dụ 2.7 Một cách khác để cấp phát mảng hai chiều A gồm M dòng và N cột như sau:
int A = new int [M]; int Tmp = new int[MN];
forint I=0;IM;++I {
A[I]=Tmp; Tmp+=N;
} Thao tác trên mảng hai chiều A
………………….. delete [] A;
delete [] A;
Tốn tử new còn có một thuận lợi khác, đó là tất cả các lỗi cấp phát động đều có thể bắt được bằng một hàm xử lý lỗi do người dùng tự định nghĩa. C++ có định nghĩa một con trỏ pointer trỏ đến hàm
đặc biệt. Khi toán tử new được sử dụng để cấp phát động và một lỗi xảy ra do cấp phát, C++ tự gọi đến hàm được chỉ bởi con trỏ này. Định nghĩa của con trỏ này như sau:
24
typedef void pvf; pvf _new_handlerpvf p;
Điều này có nghĩa là con trỏ _new_handler là con trỏ trỏ đến hàm khơng có tham số và khơng trả về giá trị. Sau khi chúng ta định nghĩa hàm như vậy và gán địa chỉ của nó cho _new_handler chúng ta có
thể bắt được tất cả các lỗi do cấp phát động.
Ví dụ 2.8:
CT2_8.CPP
1: include iostream.h 2: include stdlib.h
3: include new.h 4:
5: void MyHandler; 6:
7: unsigned long I = 0; 9; 8: void main
9: { 10: int A;
11: _new_handler = MyHandler; 12: for ; ; ++I
13: A = new int; 14:
15: } 16:
17: void MyHandler 18: {
19: coutLan cap phat thu Iendl; 20: coutKhong con du bo nhoendl;
21: exit1; 22: }
25
Sử dụng con trỏ _new_handler chúng ta phải include file new.h như ở dòng 3. Chúng ta chạy ví dụ
2.8 , kết quả ở hình 2.10.
Hình 2.10: Kết quả của ví dụ 2.8 Thư viện cũng còn có một hàm được định nghĩa trong new.h là hàm có prototype sau :
void set_new_handlervoid my_handler ; Hàm set_new_handler dùng để gán một hàm cho _new_handler.
Ví dụ 2.9:
CT2_9.CPP
1: include iostream.h 2: include new.h
3: include stdlib.h 4:
5: void MyHandler; 6:
7: int mainvoid 8: {
9: 10: char Ptr;
11: 12: set_new_handlerMyHandler;
13: Ptr = new char[64000u]; 14: set_new_handler0; Thiết lập lại giá trị mặc định
15: return 0; 16: }
17:
26
18: void MyHandler 19: {
20: cout endlKhong con du bo nho; 21: exit1;
22 }
Chúng ta chạy ví dụ 2.9
, kết quả ở hình 2.11
Hình 2.11: Kết quả của ví dụ 2.9

2.2.10 Hàm inline

Trong các chương trình C, tất cả các cấp phát động bộ nhớ đều được xử lý thông qua các hàm thư viện như malloc, calloc và free. C++ định nghĩa một phương thức mới để thực hiện việc cấp phátđộng bộ nhớ bằng cách dùng hai toán tử new và delete. Sử dụng hai toán tử này sẽ linh hoạt hơn rất nhiều so với các hàm thư viện của C. Đoạn chương trình sau dùng để cấp phát vùng nhớ động theo lốicổ điển của C.int P; P = mallocsizeofint;if P==NULL printfKhong con du bo nho de cap phat\\n;else {P = 290; printfd\\n, P;freeP; }Trong C++, chúng ta có thể viết lại đoạn chương trình trên như sau: int P;P = new int; if P==NULLcoutKhong con du bo nho de cap phat\\n; else15{ P = 290;coutP\\n; delete P;Chúng ta nhận thấy rằng, cách viết của C++ sáng sủa và dễ sử dụng hơn nhiều. Toán tử new thay thế cho hàm malloc hay calloc của C có cú pháp như sau :new type_name new type_namenew type_name initializer new type_name initializerTrong đó : type_name: Mơ tả kiểu dữ liệu được cấp phát. Nếu kiểu dữ liệumô tả phức tạp, nó có thể được đặt bên trong các dấu ngoặc.initializer: Giá trị khởi động của vùng nhớ được cấp phát.Nếu tốn tử new cấp phát khơng thành cơng thì nó sẽ trả về giá trị NULL. Còn tốn tử delete thay thế hàm free của C, nó có cú pháp như sau :delete pointer delete [] pointerChúng ta có thể vừa cấp phát vừa khởi động như sau : int P;P = new int100; if P=NULL{ coutP\\n;delete P; 16} elsecoutKhong con du bo nho de cap phat\\n; Để cấp phát một mảng, chúng ta làm như sau :int P; P = new int[10]; Cấp phát mảng 10 số nguyênif P=NULL {forint I = 0;I10;++ P[I]= I;forI = 0;I10;++ coutP[I]\\n;delete []P; }else coutKhong con du bo nho de cap phat\\n;Chú ý: Đối với việc cấp phát mảng chúng ta không thể vừa cấp phát vừa khởi động giá trị cho chúng,chẳng hạn đoạn chương trình sau là sai : int P;P = new int[10]3; Sai Ví dụ 2.6:Chương trình tạo một mảng động, khởi động mảng này với các giá trị ngẫu nhiên và sắp xếp chúng.CT2_6.CPP1: include iostream.h 2: include time.h3: include stdlib.h 4: int main175: { 6: int N;7: coutNhap vao so phan tu cua mang:; 8: cinN;9: int P=new int[N]; 10: if P==NULL11: { 12: coutKhong con bo nho de cap phat\\n;13: return 1; 14: }15: srandunsignedtimeNULL; 16: forint I=0;IN;++I17: P[I]=rand100; Tạo các số ngẫu nhiên từ 0 đến 99 18: coutMang truoc khi sap xep\\n;19: forI=0;IN;++I 20: coutP[I] ;21: forI=0;IN-1;++I 22: forint J=I+1;JN;++J23: if P[I]P[J] 24: {25: int Temp=P[I]; 26: P[I]=P[J];27: P[J]=Temp; 28: }29: cout\\nMang sau khi sap xep\\n; 30: forI=0;IN;++I31: coutP[I] ;1832: delete []P; 33: return 0;34: }Chúng ta chạy ví dụ 2.6, kết quả ở hình 2.7Hình 2.7: Kết quả của ví dụ 2.6 Ví dụ 2.7:Chương trình cộng hai ma trận trong đó mỗi ma trận được cấp phát động.Chúng ta có thể xem mảng hai chiều như mảng một chiều như hình 2.8Hình 2.8: Mảng hai chiều có thể xem như mảng một chiều. Gọi X là mảng hai chiều có kích thước m dòng và n cột.A là mảng một chiều tương ứng.Nếu X[i][j]chính là A[k] thì k = in + j Chúng ta có chương trình như sau :CT2_7.CPP1: include iostream.h192: include conio.h 3: prototype4: void AddMatrixint A,int B,intC,int M,int N; 5: int AllocMatrixint A,int M,int N;6: void FreeMatrixint A; 7: void InputMatrixint A,int M,int N,char Symbol;8: void DisplayMatrixint A,int M,int N; 9:10: int main 11: {12: int M,N; 13: int A = NULL,B = NULL,C = NULL;14: 15: clrscr;16: coutNhap so dong cua ma tran:; 17: cinM;18: coutNhap so cot cua ma tran:; 19: cinN;20: Cấp phát vùng nhớ cho ma trận A 21: if AllocMatrixA,M,N22: { endl: Xuất ra kí tự xuống dòng ‘\\n’ 23: coutKhong con du bo nhoendl;24: return 1; 25: }26: Cấp phát vùng nhớ cho ma trận B 27: if AllocMatrixB,M,N28: {2029: coutKhong con du bo nhoendl; 30: FreeMatrixA;Giải phóng vùng nhớ A31: return 1; 32: }33: Cấp phát vùng nhớ cho ma trận C 34: if AllocMatrixC,M,N35: { 36: coutKhong con du bo nhoendl;37: FreeMatrixA;Giải phóng vùng nhớ A 38: FreeMatrixB;Giải phóng vùng nhớ B39: return 1; 40: }41: coutNhap ma tran thu 1endl; 42: InputMatrixA,M,N,A;43: coutNhap ma tran thu 2endl; 44: InputMatrixB,M,N,B;45: clrscr; 46: coutMa tran thu 1endl;47: DisplayMatrixA,M,N; 48: coutMa tran thu 2endl;49: DisplayMatrixB,M,N; 50: AddMatrixA,B,C,M,N;51: coutTong hai ma tranendl; 52: DisplayMatrixC,M,N;53: FreeMatrixA;Giải phóng vùng nhớ A 54: FreeMatrixB;Giải phóng vùng nhớ B55: FreeMatrixC;Giải phóng vùng nhớ C2156: return 0; 57: }68: Cộng hai ma trận 69: void AddMatrixint A,int B,intC,int M,int N70: { 71: forint I=0;IMN;++I72: C[I] = A[I] + B[I]; 73: }74: Cấp phát vùng nhớ cho ma trận 75: int AllocMatrixint A,int M,int N76: { 77: A = new int [MN];78: if A == NULL 79: return 0;80: return 1; 81: }82: Giải phóng vùng nhớ 83: void FreeMatrixint A84: { 85: if A=NULL86: delete [] A; 87: }88: Nhập các giá trị của ma trận 89: void InputMatrixint A,int M,int N,char Symbol90: { 91: forint I=0;IM;++I92: forint J=0;JN;++J2293 { 94: coutSymbol[I][J]=;95: cinA[IN+J]; 96: }97: } 100: Hiển thị ma trận101: void DisplayMatrixint A,int M,int N 102: {103: forint I=0;IM;++I 104: {105: forint J=0;JN;++J 106: {107: out.width7;Hien thi canh le phai voi chieu dai 7 ky tu108: coutA[IN+J]; 109: }110: coutendl; 111: }112: }Chúng ta chạy ví du 2.7, kết quả ở hình 2.923Hình 2.9: Kết quả của ví dụ 2.7 Một cách khác để cấp phát mảng hai chiều A gồm M dòng và N cột như sau:int A = new int [M]; int Tmp = new int[MN];forint I=0;IM;++I {A[I]=Tmp; Tmp+=N;} Thao tác trên mảng hai chiều A………………….. delete [] A;delete [] A;Tốn tử new còn có một thuận lợi khác, đó là tất cả các lỗi cấp phát động đều có thể bắt được bằng một hàm xử lý lỗi do người dùng tự định nghĩa. C++ có định nghĩa một con trỏ pointer trỏ đến hàmđặc biệt. Khi toán tử new được sử dụng để cấp phát động và một lỗi xảy ra do cấp phát, C++ tự gọi đến hàm được chỉ bởi con trỏ này. Định nghĩa của con trỏ này như sau:24typedef void pvf; pvf _new_handlerpvf p;Điều này có nghĩa là con trỏ _new_handler là con trỏ trỏ đến hàm khơng có tham số và khơng trả về giá trị. Sau khi chúng ta định nghĩa hàm như vậy và gán địa chỉ của nó cho _new_handler chúng ta cóthể bắt được tất cả các lỗi do cấp phát động.Ví dụ 2.8:CT2_8.CPP1: include iostream.h 2: include stdlib.h3: include new.h 4:5: void MyHandler; 6:7: unsigned long I = 0; 9; 8: void main9: { 10: int A;11: _new_handler = MyHandler; 12: for ; ; ++I13: A = new int; 14:15: } 16:17: void MyHandler 18: {19: coutLan cap phat thu Iendl; 20: coutKhong con du bo nhoendl;21: exit1; 22: }25Sử dụng con trỏ _new_handler chúng ta phải include file new.h như ở dòng 3. Chúng ta chạy ví dụ2.8 , kết quả ở hình 2.10.Hình 2.10: Kết quả của ví dụ 2.8 Thư viện cũng còn có một hàm được định nghĩa trong new.h là hàm có prototype sau :void set_new_handlervoid my_handler ; Hàm set_new_handler dùng để gán một hàm cho _new_handler.Ví dụ 2.9:CT2_9.CPP1: include iostream.h 2: include new.h3: include stdlib.h 4:5: void MyHandler; 6:7: int mainvoid 8: {9: 10: char Ptr;11: 12: set_new_handlerMyHandler;13: Ptr = new char[64000u]; 14: set_new_handler0; Thiết lập lại giá trị mặc định15: return 0; 16: }17:2618: void MyHandler 19: {20: cout endlKhong con du bo nho; 21: exit1;22 }Chúng ta chạy ví dụ 2.9, kết quả ở hình 2.11Hình 2.11: Kết quả của ví dụ 2.9