2008-09-16 37 views
10

Nói rằng tôi có C++ sau:xóa bộ đệm thông qua một loại con trỏ khác?

char *p = new char[cb]; 
SOME_STRUCT *pSS = (SOME_STRUCT *) p; 
delete pSS; 

là an toàn này theo tiêu chuẩn C++? Tôi có cần quay lại char* và sau đó sử dụng delete[] không? Tôi biết nó sẽ làm việc trong hầu hết các trình biên dịch C++, bởi vì nó là dữ liệu thuần thường, không có destructors. Nó có được đảm bảo an toàn không?

Trả lời

6

Không, đó là hành vi không xác định - trình biên dịch có thể làm điều gì đó khác lạ, và như mục nhập C++ FAQ mà thudbang liên kết để nói, operator delete[] có thể bị quá tải để thực hiện điều gì đó khác với operator delete. Đôi khi bạn có thể thoát khỏi nó, nhưng nó cũng là thực hành tốt để có được thói quen kết hợp xóa [] với [] mới cho các trường hợp mà bạn không thể.

0

Trong khi này nên công việc, tôi không nghĩ rằng bạn có thể đảm bảo nó được an toàn vì các SOME_STRUCT không phải là một char * (trừ khi nó chỉ đơn thuần là một typedef).

Ngoài ra, vì bạn đang sử dụng các loại tham chiếu khác nhau, nếu bạn tiếp tục sử dụng truy cập * p và bộ nhớ đã bị xóa, bạn sẽ gặp lỗi thời gian chạy.

2

C++ chuẩn [5.3.5.2] tuyên bố:

Nếu toán hạng có kiểu lớp, các toán hạng được chuyển thành một loại con trỏ bằng cách gọi chuyển đổi nêu trên chức năng, và các toán hạng được chuyển đổi là được sử dụng thay cho toán hạng gốc cho phần còn lại của phần này. Trong giá trị thay thế, giá trị của toán hạng xóa có thể là giá trị con trỏ null. Nếu nó không phải là giá trị con trỏ null, trong giá trị thay thế đầu tiên (đối tượng xóa), giá trị của toán hạng xóa sẽ là con trỏ tới đối tượng không phải mảng hoặc con trỏ tới một đối tượng con số (1.8) lớp của một đối tượng như vậy (khoản 10). Nếu không, hành vi là không xác định. Trong phương án thứ hai thay thế (xóa mảng), giá trị của toán hạng xóa sẽ là giá trị con trỏ kết quả từ một biểu thức mới trước đó.77) Nếu không, hành vi không xác định. [Lưu ý: điều này có nghĩa là cú pháp của biểu thức xóa phải khớp với loại đối tượng được phân bổ theo mới, chứ không phải cú pháp của biểu thức mới. —end note] [Lưu ý: con trỏ đối với loại const có thể là toán hạng của biểu thức xóa; không nhất thiết phải bỏ đi constness (5.2.11) của biểu thức con trỏ trước khi nó được sử dụng như toán hạng của biểu thức xóa. —end note]

4

Tôi rất nghi ngờ điều đó.

Có rất nhiều cách để giải phóng bộ nhớ, ví dụ bạn có thể sử dụng delete trên mảng char (thay vì delete[]) và có thể hoạt động tốt. Tôi blogged chi tiết về điều này (xin lỗi vì tự liên kết, nhưng nó dễ dàng hơn viết lại tất cả).

Trình biên dịch không phải là vấn đề lớn như nền tảng. Hầu hết các thư viện sẽ sử dụng các phương pháp phân bổ của hệ điều hành cơ bản, có nghĩa là cùng một mã có thể hoạt động khác nhau trên Mac so với Windows so với Linux. Tôi đã thấy các ví dụ về điều này và mỗi một là mã có vấn đề.

Cách tiếp cận an toàn nhất là luôn phân bổ và giải phóng bộ nhớ bằng cách sử dụng cùng một kiểu dữ liệu. Nếu bạn đang phân bổ char s và hoàn trả lại các mã khác, bạn có thể được tốt hơn off cung cấp cụ thể phân bổ/phương pháp deallocate:

SOME_STRUCT* Allocate() 
{ 
    size_t cb; // Initialised to something 
    return (SOME_STRUCT*)(new char[cb]); 
} 

 

void Free(SOME_STRUCT* obj) 
{ 
    delete[] (char*)obj; 
} 

(Quá tải các toán tử newdelete cũng có thể một tùy chọn, nhưng tôi chưa bao giờ thích làm điều này.)

0

Điều này sẽ hoạt động OK nếu bộ nhớ được trỏ đến con trỏ bạn đang trỏ với cả POD. Trong trường hợp này, không có destructor nào được gọi là anyhow, và bộ cấp phát bộ nhớ không biết hoặc quan tâm đến loại được lưu trữ trong bộ nhớ.

Trường hợp duy nhất này phù hợp với loại không phải POD, nếu con trỏ là loại con của con trỏ, (ví dụ: Bạn đang trỏ vào ô tô có xe *) và trình phá hủy của con trỏ đã được khai báo là ảo.

0

Điều này không an toàn và không có phản ứng nào cho đến nay đã nhấn mạnh đủ sự điên rồ của việc này. Chỉ đơn giản là không làm điều đó, nếu bạn coi mình là một lập trình viên thực sự, hoặc muốn làm việc như một lập trình viên chuyên nghiệp trong một nhóm. Bạn chỉ có thể nói rằng cấu trúc của bạn có chứa không destructor tại thời điểm, tuy nhiên bạn đang đặt một trình biên dịch có thể khó chịu và hệ thống bẫy cụ thể cho tương lai. Ngoài ra, mã của bạn không hoạt động như mong đợi. Điều tốt nhất bạn có thể hy vọng là nó không sụp đổ. Tuy nhiên tôi nghi ngờ bạn sẽ dần dần có được một rò rỉ bộ nhớ, như phân bổ mảng thông qua mới rất thường phân bổ bộ nhớ thêm trong byte trước đến con trỏ trả về. Bạn sẽ không giải phóng bộ nhớ mà bạn nghĩ bạn đang có. Một thói quen phân bổ bộ nhớ tốt nên chọn không phù hợp này, như các công cụ như Lint, v.v.

Đơn giản là không làm điều đó, và thanh lọc từ tâm trí của bạn bất cứ quá trình suy nghĩ nào khiến bạn thậm chí xem xét những điều vô nghĩa như vậy.

0

Tôi đã thay đổi mã để sử dụng malloc/miễn phí. Trong khi tôi biết làm thế nào MSVC thực hiện mới/xóa cho đồng bằng cũ dữ liệu (và SOME_STRUCT trong trường hợp này là một cấu trúc Win32, vì vậy đơn giản C), tôi chỉ muốn biết nếu nó là một kỹ thuật di động.

Nó không phải, vì vậy tôi sẽ sử dụng cái gì đó.

0

Nếu bạn sử dụng malloc/free thay vì mới/xóa, malloc và miễn phí sẽ không quan tâm đến loại. Vì vậy, nếu bạn đang sử dụng POD giống C (dữ liệu cũ thuần túy, như kiểu dựng sẵn hoặc cấu trúc), bạn có thể malloc một loại nào đó và loại bỏ một loại khác. lưu ý rằng đây là kiểu kém ngay cả khi nó hoạt động.

2

Đây là một câu hỏi rất giống với một trong đó tôi đã trả lời ở đây: link text

Nói tóm lại, không, nó không an toàn theo chuẩn C++.Nếu vì một lý do nào đó, bạn cần một đối tượng SOME_STRUCT được phân bổ trong vùng nhớ có sự khác biệt về kích thước từ size_of(SOME_STRUCT) (và nó tốt hơn!), Thì bạn nên sử dụng hàm phân bổ thô như toàn cầu operator new để thực hiện phân bổ và sau đó tạo đối tượng đối tượng trong bộ nhớ thô với vị trí new. Vị trí new sẽ cực kỳ rẻ nếu loại đối tượng không có hàm tạo.

void* p = ::operator new(cb); 
SOME_STRUCT* pSS = new (p) SOME_STRUCT; 

// ... 

delete pSS; 

Điều này sẽ hoạt động hầu hết thời gian. Nó sẽ luôn hoạt động nếu SOME_STRUCT là cấu trúc POD. Nó cũng sẽ hoạt động trong các trường hợp khác nếu hàm tạo của SOME_STRUCT không ném và nếu SOME_STRUCT không có toán tử tùy chỉnh bị xóa. Kỹ thuật này cũng loại bỏ sự cần thiết cho bất kỳ phôi.

::operator new::operator delete tương đương gần nhất của C++ để mallocfree và như này (trong trường hợp không ghi đè lớp) đều được gọi là phù hợp bởi newdelete biểu thức họ có thể (cẩn thận!) Được sử dụng kết hợp.

Các vấn đề liên quan