2010-12-31 33 views
5

Có thể ai đó giải thích cho người lập trình C++ sự khác biệt quan trọng nhất giữa tham chiếu Java (và C#) và shared_ptr (từ Tăng hoặc từ C++ 0x).So sánh shared_ptr với tài liệu tham khảo ngôn ngữ được quản lý

Tôi hiểu rõ hơn cách thức shared_ptr được triển khai. Tôi tò mò về sự khác biệt trong các ares sau:

1) Hiệu suất. 2) Đạp xe. shared_ptr có thể được quay vòng (A và B giữ con trỏ với nhau). Có thể đi xe đạp trong Java không? 3) Còn gì nữa không?

Cảm ơn bạn.

Trả lời

4

Hiệu suất: shared_ptr hoạt động khá tốt, nhưng trong kinh nghiệm của tôi kém hiệu quả hơn quản lý bộ nhớ rõ ràng, chủ yếu là do tính tham chiếu và số tham chiếu cũng được phân bổ. Việc thực hiện tốt như thế nào phụ thuộc vào nhiều yếu tố và mức độ so sánh với Java/C# thu gom rác chỉ có thể được xác định trên cơ sở từng trường hợp sử dụng (phụ thuộc vào việc thực hiện ngôn ngữ trong các yếu tố khác).

Đi xe đạp chỉ có thể với weak_ptr, không phải với hai shared_ptr s. Java cho phép đi xe đạp mà không cần thêm quảng cáo; người thu gom rác của nó sẽ break the cycles. Tôi đoán là C# cũng vậy.

Bất cứ điều gì khác: đối tượng được trỏ đến bởi shared_ptr sẽ bị hủy ngay khi tham chiếu cuối cùng bị loại ngoài phạm vi. Destructor được gọi ngay lập tức. Trong Java, trình hoàn thiện có thể không được gọi ngay lập tức. Tôi không biết C# hoạt động như thế nào vào thời điểm này.

+3

Lưu ý về hiệu suất, nếu 'make_shared' (http://www.boost.org/doc/libs/release/libs/smart_ptr/make_shared.html) được sử dụng thì cả số tham chiếu và đối tượng được tham chiếu được phân bổ trong một khối . – dalle

+1

Có thể cho rằng, hiệu suất lớn nhất đạt được với 'shared_ptr' là tăng/giảm liên tiếp của bộ đếm ref – sbk

+0

@sbk: Tại sao bạn lại nghĩ đó là một hit hiệu suất. Nó thường được thực hiện như một hướng dẫn lắp ráp đơn (không cần một khóa trên phần cứng hỗ trợ nó ngầm). –

3

Sự khác biệt chính là khi số lượng sử dụng của con trỏ chia sẻ là 0, đối tượng nó trỏ đến bị hủy (destructor được gọi và đối tượng được deallocated), ngay lập tức. Trong Java và C# việc deallocation của đối tượng được hoãn lại cho đến khi Garbage Collector chọn để deallocate đối tượng (tức là, nó không xác định).

Đối với chu kỳ, tôi không chắc mình hiểu ý của bạn là gì. Nó khá phổ biến trong Java và C# để có hai đối tượng có chứa các trường thành viên tham chiếu đến nhau, do đó tạo ra một chu kỳ. Ví dụ như một chiếc xe hơi và một động cơ - chiếc xe đề cập đến động cơ thông qua một lĩnh vực động cơ và động cơ có thể tham khảo xe của nó thông qua một lĩnh vực xe hơi.

+1

Không có các trình phá hủy "bình thường" trong C# và Java, chúng chỉ có các trình làm mịn, được coi là một sự không phù hợp trong các ngôn ngữ đó. Destructors và thu gom rác thải là tỷ lệ cược. GC về cơ bản có nghĩa là: không có sự hủy diệt, hoặc thời gian sống đối tượng vô hạn. –

+0

Có một sự khác biệt giữa khái niệm của một destructor, như trong một hàm, được gọi và sự hủy diệt của một đối tượng, như trong deallocation của nó. Tôi biết điều này thường có thể gây nhầm lẫn bởi vì cùng một thuật ngữ được sử dụng cho cả hai sự kiện này, vì vậy có lẽ đối tượng deallocation sẽ là một sự lựa chọn tốt hơn của các từ để tham khảo sự kiện sau này. –

+4

hủy diệt không phải là deallocation, họ là những khái niệm rất khác nhau và không nên được sử dụng thay thế cho nhau. –

1

Tham chiếu chu kỳ với các con trỏ được tính tham chiếu C++ sẽ không được xử lý. Bạn có thể sử dụng con trỏ yếu để làm việc xung quanh điều này. Các tham chiếu chu kỳ trong Java hoặc C# có thể được xử lý, khi bộ thu gom rác cảm thấy giống như nó.

Khi số đếm trong con trỏ được tính tham chiếu C++ giảm xuống 0, hàm hủy được gọi. Khi một đối tượng Java không thể truy cập được nữa, trình hoàn thiện của nó có thể không được gọi nhanh chóng hoặc không bao giờ. Do đó, đối với các đối tượng yêu cầu xử lý rõ ràng tài nguyên bên ngoài, một số dạng gọi rõ ràng là bắt buộc.

1

Trước hết, Java/C# chỉ có con trỏ, không tham chiếu, mặc dù chúng gọi chúng như vậy. Tham chiếu là một tính năng C++ duy nhất. Thu gom rác trong Java/C# về cơ bản có nghĩa là thời gian sống vô hạn. Mặt khác, shared_ptr cung cấp sự chia sẻ và phá hủy xác định, khi số đếm đến 0. Do đó, shared_ptr có thể được sử dụng để tự động quản lý mọi tài nguyên, không chỉ cấp phát bộ nhớ. Trong một ý nghĩa (giống như bất kỳ thiết kế RAII) nó biến ngữ nghĩa con trỏ thành ngữ nghĩa giá trị mạnh mẽ hơn.

+4

Phân biệt C++ giữa "con trỏ" và "tham chiếu" khá cụ thể với ngôn ngữ đó. C#/Java tham chiếu là một nơi nào đó ở giữa hai, vì bạn không thể làm số học con trỏ trên chúng. –

+0

@larsmans, Vấn đề là Java, ngữ nghĩa, không chỉ có con trỏ, nhưng nó chỉ có con trỏ. Nó thiếu một cơ chế tham chiếu đảm bảo rằng tham chiếu không bao giờ là rỗng. Nhưng nó thực sự không có con trỏ arithmetics, và các ký hiệu cú pháp bề ngoài không phải là ký hiệu con trỏ bình thường. –

+0

nhưng những gì bạn đang nói là gây hiểu nhầm vì nó giả định định nghĩa C++ về "tham chiếu" là gì. Java có các tham chiếu vì chúng được gọi là các tham chiếu. Họ chỉ không cư xử như tài liệu tham khảo C++. – jalf

1

Không ai chỉ khả năng di chuyển đối tượng bằng trình quản lý bộ nhớ trong bộ nhớ được quản lý.Vì vậy, trong C# không có tham chiếu đơn giản/con trỏ, chúng hoạt động giống như ID mô tả đối tượng được trả về bởi người quản lý.
Trong C++ bạn không thể đạt được điều này với shared_ptr, bởi vì đối tượng vẫn ở trong cùng một vị trí sau khi nó đã được tạo.

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