2009-06-05 5 views
20

Trong C thực tế ++ chuẩn, tạo ra bộ sưu tập thỏa mãn quy tắc sau đây là khó khăn nếu không muốn nói là không thể:unique_ptr - cải tiến chính?

  1. ngoại lệ an toàn,
  2. hoạt động giá rẻ nội bộ (trong STL container thực tế: các hoạt động là bản sao),
  3. tự động quản lý bộ nhớ.

Để đáp ứng (1), bộ sưu tập không thể lưu trữ con trỏ thô. Để thỏa mãn (2), một bộ sưu tập phải lưu trữ các con trỏ thô. Để thỏa mãn (3), một tập hợp phải lưu trữ các đối tượng theo giá trị.

Kết luận: ba mục xung đột với nhau.

Mục (2) sẽ không được thỏa mãn khi shared_ptr được sử dụng vì khi bộ sưu tập cần di chuyển một phần tử, nó sẽ cần thực hiện hai cuộc gọi: tới một hàm tạo và hủy. Không có hoạt động lớn, memcpy() giống như sao chép/di chuyển là có thể.

Tôi có đúng là vấn đề được mô tả sẽ được giải quyết bởi unique_ptrstd::move()? Bộ sưu tập sử dụng các công cụ này sẽ có thể đáp ứng tất cả 3 điều kiện:

  1. Khi một bộ sưu tập sẽ bị xóa như một tác dụng phụ của một ngoại lệ, nó sẽ gọi hàm hủy unique_ptr 's. Không bị rò rỉ bộ nhớ.
    • unique_ptr không cần thêm dung lượng cho bộ đếm tham chiếu; do đó cơ thể của nó nên được chính xác kích thước tương tự như con trỏ quấn,
    • Tôi không chắc chắn, nhưng có vẻ như điều này cho phép di chuyển các nhóm unique_ptrs bằng cách sử dụng memmove() như hoạt động (?),
    • ngay cả khi nó không thể, toán tử std::move() sẽ cho phép di chuyển từng đối tượng unique_ptr mà không thực hiện cuộc gọi cặp hàm tạo/phá hủy.
  2. unique_ptr sẽ có độc quyền sở hữu bộ nhớ đã cho. Không có rò rỉ bộ nhớ ngẫu nhiên sẽ có thể.

Điều này có đúng không? Những lợi thế khác của việc sử dụng unique_ptr là gì?

+6

Nếu yopu muốn viết blog, vui lòng làm như vậy - nhưng không phải ở đây. –

+3

@Neil: Đây là một câu hỏi cụ thể, vấn đề là với nền tảng lớn mà tôi phải đưa vào. Nó * là * hữu ích, ví dụ như câu trả lời của James Hopkin, rằng memcopy() - giống như các hoạt động không làm cho nó thành bản nháp. Làm thế nào khác là tôi giả sử để hỏi về điều đó? Không có nền? Không ai hiểu được! –

+2

Có lẽ nó sẽ được yêu cầu tốt hơn là 'những lợi thế của unique_ptr' là gì. Bạn luôn có thể trả lời câu hỏi của riêng bạn. –

Trả lời

6

Tôi đồng ý hoàn toàn. Có một cách tự nhiên để xử lý các đối tượng được phân bổ heap.

Trong câu trả lời cho:

Tôi không chắc chắn, nhưng có vẻ như điều này cho phép di chuyển các nhóm unique_ptr s bằng cách sử dụng memmove() như các hoạt động,

có một proposal cho phép điều này , nhưng nó đã không làm cho nó thành tiêu chuẩn C++ 11.

2

Có, bạn đã đúng. Tôi sẽ chỉ thêm điều này là có thể nhờ tham chiếu giá trị r.

1

Có vẻ như ba điều kiện tôi đã liệt kê trong bài đăng của mình có thể nhận được bằng cách sử dụng Boost Pointer Container Library.

0

Câu hỏi này không hiểu tại sao tôi lại yêu thích số Boehm garbage collector (libgc). Không bao giờ cần phải sao chép bất cứ điều gì vì lý do quản lý bộ nhớ, và thực sự, quyền sở hữu bộ nhớ không còn cần phải được đề cập như là một phần của API. Bạn phải mua thêm một chút RAM để có được hiệu suất CPU tương tự, nhưng bạn tiết kiệm được hàng trăm giờ lập trình viên. Bạn quyết định.

+9

Thời gian tạm dừng trên Boehm GC là khủng khiếp. Ngay cả Java cũng tốt hơn. – Zifre

+0

Tôi nghĩ rằng toàn bộ ý tưởng ở đây là ở cách xa những người thu gom rác. –

2

Khi bộ sưu tập sẽ bị xóa dưới dạng tác dụng phụ của ngoại lệ, nó sẽ gọi trình hủy độc đáo của unique_ptr. Không bị rò rỉ bộ nhớ.

Có, hộp chứa unique_ptr sẽ đáp ứng điều này.

unique_ptr không cần thêm dung lượng cho bộ đếm tham chiếu; do đó cơ thể của nó phải chính xác cùng kích thước, như con trỏ được gói

unique_ptr kích thước được thực hiện xác định. Mặc dù tất cả việc triển khai hợp lý của unique_ptr bằng cách sử dụng hàm hủy mặc định sẽ chỉ có thể là kích thước con trỏ, không có bảo đảm trong tiêu chuẩn này.

Tôi không chắc chắn, nhưng có vẻ như điều này cho phép di chuyển các nhóm unique_ptrs bằng cách sử dụng memmove() như hoạt động (?),

Tuyệt đối không. unique_ptr không phải là một lớp tầm thường; do đó, nó không thể là memmove d xung quanh. Ngay cả khi nó đã được, bạn không thể chỉ memmove chúng, bởi vì các destructors cho bản gốc cần phải được gọi là. Nó sẽ phải là một memmove, theo sau là memset.

ngay cả khi không thể, toán tử std :: move() sẽ cho phép di chuyển từng đối tượng unique_ptr mà không thực hiện lệnh gọi hàm tạo/phá hủy.

Cũng không chính xác. Phong trào không làm cho các nhà thầu và các nhà hủy diệt không được gọi. unique_ptr đang bị phá hủy cần phải được bị phá hủy; đòi hỏi một cuộc gọi đến những kẻ hủy diệt của họ. Tương tự, unique_ptr s mới cần phải có các hàm tạo của chúng được gọi; đó là cách bắt đầu của một đối tượng.

Không tránh điều đó; đó là cách C++ hoạt động.

Tuy nhiên, đó không phải là điều bạn nên lo lắng. Thành thật mà nói, nếu bạn lo ngại về một lời gọi hàm tạo/phá hủy đơn giản, bạn đang ở trong mã mà bạn nên tối ưu hóa bằng tay (và do đó viết mã của riêng bạn), hoặc bạn đang tối ưu hóa sớm mã của mình. Điều gì quan trọng không phải là liệu các nhà xây dựng/destructors được gọi là; điều quan trọng là mã kết quả nhanh như thế nào.

unique_ptr sẽ có độc quyền sở hữu bộ nhớ đã cho. Không có rò rỉ bộ nhớ ngẫu nhiên sẽ có thể.

Có, nó sẽ.

Cá nhân, tôi muốn nói rằng bạn đang làm một trong những điều sau đây:

  • Là quá hoang tưởng về việc sao chép các đối tượng. Đây là bằng chứng của thực tế là bạn xem xét đặt một shared_ptr trong một container là quá tốn kém của một bản sao. Đây là một căn bệnh quá phổ biến trong số các lập trình viên C++. Đó không phải là để nói rằng sao chép luôn luôn là tốt hay một cái gì đó, nhưng ám ảnh về việc sao chép một shared_ptr trong một container là vô lý bên ngoài hoàn cảnh đặc biệt.

  • Không biết cách sử dụng đúng ngữ nghĩa di chuyển. Nếu đối tượng của bạn đắt tiền để sao chép nhưng rẻ tiền để di chuyển ... thì hãy di chuyển chúng vào trong thùng chứa. Không có lý do để có một con trỏ indirection khi đối tượng của bạn đã có indirections con trỏ. Chỉ cần sử dụng chuyển động với chính các đối tượng, không phải là unique_ptr s đối với các đối tượng.

  • Bỏ qua các lựa chọn thay thế. Cụ thể là Boost's pointer containers. Họ dường như có mọi thứ bạn muốn. Chúng sở hữu các con trỏ tới các đối tượng của chúng, nhưng bên ngoài chúng có các ngữ nghĩa giá trị hơn là các ngữ nghĩa của con trỏ. Chúng an toàn ngoại lệ và mọi sự sao chép xảy ra với con trỏ. No unique_ptr constructor/destructor "overhead".