Thế giới mà Bjarne sống trong đó rất ... hàn lâm, vì muốn có một thuật ngữ tốt hơn. Nếu mã của bạn có thể được thiết kế và cấu trúc sao cho các đối tượng có hệ thống phân cấp quan hệ rất có chủ ý, thì các mối quan hệ sở hữu là cứng nhắc và không chịu được, mã sẽ chảy theo một hướng (từ cấp cao đến cấp thấp) và các đối tượng chỉ nói chuyện với những người thấp hơn hệ thống phân cấp, sau đó bạn sẽ không tìm thấy nhiều nhu cầu shared_ptr
. Đó là thứ bạn sử dụng trong những dịp hiếm hoi mà ai đó phải phá vỡ quy tắc. Nhưng nếu không, bạn chỉ có thể gắn mọi thứ trong vector
s hoặc các cấu trúc dữ liệu khác sử dụng ngữ nghĩa giá trị và unique_ptr
s cho những thứ bạn phải phân bổ đơn lẻ.
Mặc dù đó là một thế giới tuyệt vời để sống, nhưng đó không phải là điều bạn có thể làm mọi lúc. Nếu bạn không thể tổ chức mã của mình theo cách đó, bởi vì thiết kế hệ thống mà bạn đang cố gắng thực hiện có nghĩa là không thể (hoặc chỉ rất khó chịu), thì bạn sẽ thấy mình cần sở hữu chung các đối tượng ngày càng nhiều .
Trong một hệ thống như vậy, việc giữ các con trỏ trần trụi ... không chính xác là nguy hiểm, nhưng nó đặt ra câu hỏi. Điều tuyệt vời shared_ptr
là nó cung cấp các đảm bảo cú pháp hợp lý về tuổi thọ của đối tượng. Nó có thể bị phá vỡ? Tất nhiên. Nhưng mọi người cũng có thể const_cast
mọi thứ; chăm sóc cơ bản và cho ăn shared_ptr
phải cung cấp chất lượng cuộc sống hợp lý cho các đối tượng được phân bổ, quyền sở hữu phải được chia sẻ.
Sau đó, có weak_ptr
s, không thể được sử dụng trong trường hợp không có a shared_ptr
. Nếu hệ thống của bạn có cấu trúc cứng nhắc, thì bạn có thể lưu trữ một con trỏ trần cho một đối tượng nào đó, an toàn với kiến thức rằng cấu trúc của ứng dụng đảm bảo rằng đối tượng được chỉ ra sẽ tồn tại lâu hơn bạn. Bạn có thể gọi một hàm trả về một con trỏ tới một giá trị bên trong hoặc bên ngoài (ví dụ tìm đối tượng có tên X). Trong mã được cấu trúc đúng, chức năng đó sẽ chỉ khả dụng cho bạn nếu tuổi thọ của đối tượng được đảm bảo vượt quá chính bạn; do đó, lưu trữ con trỏ trần trong đối tượng của bạn là tốt.
Vì sự cứng nhắc đó không phải lúc nào cũng có thể đạt được trong các hệ thống thực, bạn cần một số cách để đảm bảo hợp lý trọn đời. Đôi khi, bạn không cần quyền sở hữu đầy đủ; đôi khi, bạn chỉ cần có thể biết khi nào con trỏ xấu hay tốt. Đó là nơi weak_ptr
xuất hiện. Đã có trường hợp tôi có thể sử dụng unique_ptr
hoặc boost::scoped_ptr
, nhưng tôi phải sử dụng shared_ptr
vì tôi đặc biệt cần thiết để đưa cho ai đó một con trỏ "dễ bay hơi". Một con trỏ mà cả đời không xác định được và chúng có thể truy vấn khi con trỏ đó bị phá hủy.
Một cách an toàn để tồn tại khi tình trạng của thế giới là không xác định.
Có thể điều đó đã được thực hiện bởi một số lệnh gọi hàm để lấy con trỏ, thay vì thông qua weak_ptr
? Có, nhưng điều đó có thể dễ dàng bị phá vỡ hơn. Một hàm trả về một con trỏ trần không có cách nào về mặt cú pháp gợi ý rằng người dùng không làm điều gì đó giống như lưu trữ con trỏ đó lâu dài. Trả lại một cái shared_ptr
cũng khiến cho ai đó dễ dàng lưu trữ nó và có khả năng kéo dài tuổi thọ của một vật thể. weak_ptr
Tuy nhiên, việc trả lại một gợi ý mạnh mẽ rằng lưu trữ những shared_ptr
gì bạn nhận được lock
là một ... ý tưởng đáng ngờ. Nó sẽ không ngăn bạn làm điều đó, nhưng không có gì trong C ++ ngăn bạn phá mã. weak_ptr
cung cấp một số sức đề kháng tối thiểu từ việc làm điều tự nhiên.
Bây giờ, điều đó không có nghĩa là shared_ptr
không thể sử dụng quá mức ; nó chắc chắn có thể Đặc biệt là trước unique_ptr
đó, có nhiều trường hợp tôi chỉ sử dụng một boost::shared_ptr
vì tôi cần phải vượt qua một con trỏ RAII xung quanh hoặc đưa nó vào một danh sách. Không có ngữ nghĩa di chuyển và unique_ptr
, boost::shared_ptr
là giải pháp thực sự duy nhất.
Và bạn có thể sử dụng nó ở những nơi khá cần thiết. Như đã nêu ở trên, cấu trúc mã thích hợp có thể loại bỏ nhu cầu sử dụng một số shared_ptr
. Nhưng nếu hệ thống của bạn không thể được cấu trúc như vậy và vẫn làm những gì nó cần, shared_ptr
sẽ được sử dụng đáng kể.