Xóa một con trỏ tới const (T const *)


89

Tôi có một câu hỏi cơ bản liên quan đến con trỏ const. Tôi không được phép gọi bất kỳ hàm thành viên không phải const nào bằng cách sử dụng con trỏ const. Tuy nhiên, tôi được phép làm điều này trên một con trỏ const:

delete p;

Điều này sẽ gọi hàm hủy của lớp mà về bản chất là một 'phương thức' không phải const. Tại sao điều này được cho phép? Nó chỉ để hỗ trợ điều này:

delete this;

Hay là một số lý do khác?

Câu trả lời:


112

Nó để hỗ trợ:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Nhưng lưu ý rằng vấn đề không chỉ giới hạn ở các đối tượng được tạo động:

{
 const Foo f;
 // use it
} // destructor called here

Nếu các hàm hủy không thể được gọi trên các đối tượng const, chúng ta hoàn toàn không thể sử dụng các đối tượng const.


21
+1 cho bản chỉnh sửa mới nhất của bạn. Tôi nghĩ đây là lý do đúng. Lệnh gọi hàm hủy tự động cho đối tượng const - gần giống như delete f; trong đó f - con trỏ trên const.
bayda

const Foo * fhoặc Foo const * fkhông phải là một con trỏ const tới Foo. Thật là khó hiểu đối với const Foo. Foo * const f là một con trỏ const tới Foo.
dùng11373693

48

Nói theo cách này - nếu nó không được phép sẽ không có cách nào để xóa các đối tượng const mà không sử dụng const_cast.

Về mặt ngữ nghĩa, const là một chỉ báo rằng một đối tượng phải là bất biến. Tuy nhiên, điều đó không có nghĩa là không nên xóa đối tượng.


3
Kẻ hủy diệt có thể biến đổi vật thể theo những cách khá bạo lực, vì vậy đây hẳn là một cách sử dụng kỳ lạ của từ 'bất biến' mà trước đây tôi không biết ...
DarthGizka

1
@DarthGizka không, hàm hủy đưa bạn từ trạng thái có đối tượng đến trạng thái không có. C ++ không xác định bất kỳ phương pháp để quan sát một "đột biến" hậu sự hủy diệt
Caleth

@ Caleth: tiêu chuẩn có thể không cho phép bạn nhìn vào đối tượng sau khi trình hủy của nó đã chạy xong, nhưng bạn chắc chắn được phép xem xét các tác dụng phụ do việc phá hủy gây ra. Do đó, hoàn cảnh có thể dễ dàng được sắp xếp để làm cho sự đột biến của đối tượng quan sát 'bất biến'. Ở Mỹ, tội giết người rất khó khởi tố khi không có xác, nhưng vẫn là tội giết người (và có thể có bằng chứng khác đủ để kết tội). Cùng một sự khác biệt.
DarthGizka 27/09/18

6

Tôi không được phép gọi bất kỳ hàm thành viên không phải const nào bằng cách sử dụng con trỏ const.

Có bạn.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Bạn đã nhầm lẫn một con trỏ const với một đối tượng không phải const, với một con trỏ không const với một đối tượng const.

Có nói rằng,

delete aConstPointer; // legal
delete aPointerToConst; // legal

hợp pháp để xóa một trong hai, vì những lý do đã được nêu trong các câu trả lời khác ở đây.


5

Các cấu trúc và trình hủy không nên được xem là 'phương thức'. Chúng là các cấu trúc đặc biệt để khởi tạo và chia nhỏ một đối tượng của một lớp.

'Con trỏ const' là để chỉ ra rằng trạng thái của đối tượng sẽ không bị thay đổi khi các hoạt động được thực hiện trên nó khi nó còn sống.


5

Một cách khác để xem xét nó: ý nghĩa chính xác của con trỏ const là bạn sẽ không thể thực hiện các thay đổi đối với đối tượng trỏ tới sẽ được hiển thị qua con trỏ đó hoặc bất kỳ con trỏ nào khác hoặc tham chiếu đến cùng một đối tượng. Nhưng khi một đối tượng bị hủy, tất cả các con trỏ khác đến địa chỉ mà đối tượng đã bị xóa trước đó chiếm giữ không còn là con trỏ đến đối tượng đó nữa. Chúng lưu trữ cùng một địa chỉ, nhưng địa chỉ đó không còn là địa chỉ của bất kỳ đối tượng nào (trên thực tế, nó có thể sớm được sử dụng lại làm địa chỉ của một đối tượng khác).

Sự khác biệt này sẽ rõ ràng hơn nếu các con trỏ trong C ++ hoạt động như các tham chiếu yếu, tức là ngay sau khi đối tượng bị phá hủy, tất cả các con trỏ còn tồn tại đến nó sẽ ngay lập tức được đặt thành 0. (Đó là loại thứ được coi là quá tốn kém trong thời gian chạy để áp đặt cho tất cả các chương trình C ++ và trên thực tế là không thể làm cho nó hoàn toàn đáng tin cậy.)

CẬP NHẬT : Đọc lại điều này chín năm sau, đó là luật sư. Bây giờ tôi thấy phản ứng ban đầu của bạn có thể hiểu được. Không cho phép đột biến nhưng cho phép phá hủy rõ ràng là có vấn đề. Hợp đồng ngụ ý của các con trỏ / tham chiếu const là sự tồn tại của chúng sẽ hoạt động như một khối phá hủy đối tượng đích, hay còn gọi là thu gom rác tự động.

Giải pháp thông thường cho điều này là sử dụng hầu hết các ngôn ngữ khác để thay thế.


Nếu bạn không thể phá hủy những thứ được trỏ đến bởi con trỏ tới const, bạn làm thế nào để đối phó với một std::unique_ptr<const T>kết thúc là cuộc sống?
Caleth

@Caleth thì sẽ không có giải pháp nào cho điều đó trong C ++. Đó chỉ là một ví dụ về vấn đề chung: trong C ++, công cụ sửa đổi const có nghĩa là “Bạn không thể thay đổi mục tiêu, ngoại trừ một nghĩa nào đó, bạn hoàn toàn có thể phá hủy nó và làm cho tất cả các tham chiếu khác đến nó không hợp lệ và nguồn của hành vi không xác định”. Đây là lý do tại sao tôi nghĩ loại câu hỏi này nên hoạt động như một lời nhắc nhở để xem xét các ngôn ngữ khác. Nó có các lỗ hổng UB trong đó không thể được giải quyết nếu không thực hiện một cách tiếp cận cơ bản khác.
Daniel Earwicker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.