PDA

View Full Version : con trỏ và delete trong C++



nuilua3
20-05-2005, 19:05
Hi.Tui lai co mot van de nho,do la chuong trinh
#include "iostream.h"
#include "conio.h"
void main()
{
char *st="hom nay";
char *p;
p=new char[strlen(st)+1];
delete p;
cout<<p;
}
output la:homnay.
Tui muon hoi la tai sao lenh delete tren khong co tac dung.(Tui dung tren TCW4.5 .Khi tui test tren TC 3.0 thi lenh van delete co tac dung)

mtt333
21-05-2005, 22:47
Có thể TCW4.5 có vấn đề gì đó mà mình không biết vì mình không dùng nó bao giờ.

Còn trong phần lớn trình dịch:

Đoạn trình trên không thể in ra "hom nay" được dù bạn có hoặc không có lệnh delete vì toán tử new ở trên chỉ tạo ra một vùng nhớ chứa đủ xâu st mà chưa hề thực hiện thao tác sao chép nội dung xâu st cho p được.

Có lẽ chương trình của bnạ phải thế này mới thì mới có thể bàn đến lệnh delete được:
void main()
{
char *st="hom nay";
char *p;
p=new char[strlen(st)+1];
strcpy(p, st);
delete p;
cout<<p;
}

Lệnh delete mới chỉ thực hiện công việc giải phóng vùng nhớ tức là đánh dấu vùng nhớ do p trỏ tới là free. Việc tiếp theo là tuỳ thuộc vào tuỳ bộ dịnh và tuỳ môi trường.
Giả sử bộ dịch không gán NULL cho p sau lệnh delete và hệ điều hành không cấm chương trình của bạn truy cập vào vùng nhớ do p trỏ tới thì:
- Nếu các chương trình khác chưa sử dụng vùng nhớ này thì chuỗi "hôm nay" vẫn có thể tồn tại trong bộ nhớ --> có thể in ra chuỗi này do p trỏ tới
- Nếu các chương trình khác (trong các hệ điều hành đa nhiệm) hoặc thậm chí ngay cả chính chương trình này của bạn sử dụng vùng nhớ này thì KQ không còn là chuỗi "hom nay" nữa.

Có thể xảy ra trường hợp hệ điều hành ngăn cản, cấm không cho bạn truy cập vào vùng nhớ do p kiểm soát --> báo lỗi khi cout<<p
Cũng có thể bộ dịch thực hiện thao tác gán NULL cho p sau lệnh delete --> không thể truy cập vùng nhớ này.

Lời khuyên: gán NULL cho p ngay sau khi delete, điều này đặc biệt cần thiết nếu p là biến toàn cụ hoặc p là một con trỏ được sử dụng để quản lý vùg dữ liệu động của bạn.

Ngô Huy Ánh
22-05-2005, 02:06
Theo như mình hiểu thì:
p = new char[..];
đây là bạn khai báo một mảng các phần tử kiểu char(nằm trong vùng heap)
khi delete phải viết:
delete [] p;
Lúc này bộ nhớ cấp phát cho p mới được giải phóng hoàn toàn.
Còn delete p; thì nó chỉ giải phóng phần tử đầu tiên của mảng thôi, tức là chỉ giải phóng p[0];

mtt333
22-05-2005, 08:18
Theo như mình hiểu thì:
p = new char[..];
đây là bạn khai báo một mảng các phần tử kiểu char(nằm trong vùng heap)
khi delete phải viết:
delete [] p;
Lúc này bộ nhớ cấp phát cho p mới được giải phóng hoàn toàn.
Còn delete p; thì nó chỉ giải phóng phần tử đầu tiên của mảng thôi, tức là chỉ giải phóng p[0];

Không chính xác.
Khi gọi delete bạn đã giải phóng toàn bộ vùng nhớ động được cấp phát bởi new do p trỏ tới.
Bạn có thẻ kiểm nghiệm điều này qua các ví dụ lập trình hoặc tìm đọc cuốn
"Lập trình hướng đối tượng với C++, Nguyễn Thanh Thuỷ (chủ biên), NXB Khoa học kỹ thuật, 2003", tr 36

DavidGoose
22-05-2005, 12:14
Không chính xác.
Khi gọi delete bạn đã giải phóng toàn bộ vùng nhớ động được cấp phát bởi new do p trỏ tới.
Bạn có thẻ kiểm nghiệm điều này qua các ví dụ lập trình hoặc tìm đọc cuốn
"Lập trình hướng đối tượng với C++, Nguyễn Thanh Thuỷ (chủ biên), NXB Khoa học kỹ thuật, 2003", tr 36
Cai nay qua' chi'nh xa'c day.Van de la` con tro p no' tro den vu`ng nho na`o, mot khi khai ba'o new char[...] neu ban du`ng delete thi` se bi memory leak->fatal error ;)


Có thể TCW4.5 có vấn đề gì đó mà mình không biết vì mình không dùng nó bao giờ.

Còn trong phần lớn trình dịch:

Đoạn trình trên không thể in ra "hom nay" được dù bạn có hoặc không có lệnh delete vì toán tử new ở trên chỉ tạo ra một vùng nhớ chứa đủ xâu st mà chưa hề thực hiện thao tác sao chép nội dung xâu st cho p được.

Có lẽ chương trình của bnạ phải thế này mới thì mới có thể bàn đến lệnh delete được:
void main()
{
char *st="hom nay";
char *p;
p=new char[strlen(st)+1];
strcpy(p, st);
delete p;
cout<<p;
}

Lệnh delete mới chỉ thực hiện công việc giải phóng vùng nhớ tức là đánh dấu vùng nhớ do p trỏ tới là free. Việc tiếp theo là tuỳ thuộc vào tuỳ bộ dịnh và tuỳ môi trường.
Giả sử bộ dịch không gán NULL cho p sau lệnh delete và hệ điều hành không cấm chương trình của bạn truy cập vào vùng nhớ do p trỏ tới thì:
- Nếu các chương trình khác chưa sử dụng vùng nhớ này thì chuỗi "hôm nay" vẫn có thể tồn tại trong bộ nhớ --> có thể in ra chuỗi này do p trỏ tới
- Nếu các chương trình khác (trong các hệ điều hành đa nhiệm) hoặc thậm chí ngay cả chính chương trình này của bạn sử dụng vùng nhớ này thì KQ không còn là chuỗi "hom nay" nữa.

Có thể xảy ra trường hợp hệ điều hành ngăn cản, cấm không cho bạn truy cập vào vùng nhớ do p kiểm soát --> báo lỗi khi cout<<p
Cũng có thể bộ dịch thực hiện thao tác gán NULL cho p sau lệnh delete --> không thể truy cập vùng nhớ này.

Lời khuyên: gán NULL cho p ngay sau khi delete, điều này đặc biệt cần thiết nếu p là biến toàn cụ hoặc p là một con trỏ được sử dụng để quản lý vùg dữ liệu động của bạn.

Ca'i na`y thi` chi'nh xa'c.
Delete p, tri`nh dich sẽ trả lại phần bộ nhớ chiếm bởi p cho heap. Nhưng p vẫn giữ giá trị địa chỉ của vùng nhớ nói trên.
cout << p, câu lệnh sẽ tự nhận dạng kiểu dữ liệu, p là char *, nó dò tìm dữ liệu bắt đầu từ p đến zero terminated và print out, nó cũng chẳng quan tâm đến việc p đã free hay chưa.
p = NULL: Cái này thông thường là thói quen rất tốt. Nhưng tốt hơn nên gán
p = 0. NULL là một thứ không tương thích giữa các C/C++ compilers.

Kijuto Riddle
22-05-2005, 22:12
delete gọi destructor nếu p là con trỏ object. Sau đó, nó sẽ gọi ::free(p) (nếu chưa có ai overload cái toán tử delete). Tiếp đó, hàm ::free(p) sẽ "đánh dấu" rằng vùng nhớ được cấp cho p trước đó không dùng nữa. Giá trị của p và dữ liệu tại vùng nhớ vẫn được giữ nguyên hay bị thay đổi thì phụ thuộc hoàn toàn vào trình biên dịch. Về phương diện lập trình, nếu đã ::free(p)/delete p; thì không được dùng dữ liệu ở vùng nhớ p trỏ tới nữa, bởi vì dữ liệu đó đã không xác định (không được quản lý bởi chương trình) và nó có thể có bất cứ giá trị nào nó có thể. Nếu cứ dùng, sẽ không ai trả tiền bảo hiểm cho các bạn đâu. :)