có thể đạt được mô hình sở hữu của Rust với trình bao bọc C ++ chung không?


15

Xem qua bài viết này về an toàn đồng thời của Rust:

http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html

Tôi đã tự hỏi có bao nhiêu trong số những ý tưởng này có thể đạt được trong C ++ 11 (hoặc mới hơn). Cụ thể tôi có thể tạo một lớp chủ sở hữu chuyển quyền sở hữu sang bất kỳ phương thức nào mà nó có thể được thông qua không? Có vẻ như C ++ có rất nhiều cách để truyền các biến đến mức không thể, nhưng có lẽ tôi có thể đặt một số hạn chế đối với lớp hoặc khuôn mẫu để đảm bảo rằng một số mã mẫu được thực thi với mỗi lần truyền phương thức?


Một số trích dẫn từ liên kết sẽ cải thiện câu hỏi này
Martin Ba

2
@delnan (An toàn) Rust đảm bảo rằng bạn không bao giờ có nhiều hơn một tài liệu tham khảo có thể thay đổi tại một thời điểm và bạn không bao giờ có một tài liệu tham khảo có thể thay đổi đến một điều mà bạn cũng có tài liệu tham khảo chỉ đọc. Nó cũng có một số hạn chế trong việc chuyển dữ liệu giữa các luồng. Cùng nhau, điều này ngăn chặn một lớp đáng kể các lỗi liên quan đến luồng và làm cho lý luận về trạng thái của các đối tượng dễ dàng hơn, ngay cả trong mã đơn.
CodeInChaos

3
Bạn không nghĩ rằng bạn có thể thể hiện việc vay mượn theo cách mà trình biên dịch C ++ có thể xác minh, vì vậy bạn phải dùng đến việc thực thi thời gian chạy với lần nhấn hiệu suất liên quan.
CodeInChaos

1
Không phải quyền sở hữu phạm vi đã được triển khai bởi con trỏ thông minh trong C ++ 11?
Akshat Mahajan

1
@JerryJeremiah Rust có nhiều loại tham khảo. Những cái cơ bản, &không yêu cầu bất kỳ loại quảng cáo nào được sử dụng. Nếu bạn cố gắng một &mutlúc, bạn vẫn có một tài liệu tham khảo khác (có thể thay đổi hoặc không) cho cùng một mục, bạn sẽ không thể biên dịch. RefCell<T>di chuyển kiểm tra để chạy thời gian, vì vậy bạn sẽ hoảng loạn nếu bạn cố gắng để .borrow_mut()một cái gì đó đã có hoạt động .borrow()hoặc .borrow_mut(). Rust cũng có Rc<T>(con trỏ sở hữu chung) và anh chị em của nó Weak<T>, nhưng đó là về quyền sở hữu, không phải là khả năng biến đổi. Dán một RefCell<T>bên trong chúng cho khả năng biến đổi.
8bittree

Câu trả lời:


8

C ++ có ba cách để truyền tham số cho hàm: theo giá trị, theo tham chiếu lvalue và bằng tham chiếu rvalue. Trong số này, truyền theo giá trị tạo ra quyền sở hữu theo nghĩa là hàm được gọi nhận bản sao của chính nó và chuyển qua tham chiếu giá trị chỉ ra rằng giá trị có thể được tiêu thụ, tức là sẽ không được người gọi sử dụng nữa. Vượt qua tham chiếu lvalue có nghĩa là đối tượng được mượn tạm thời từ người gọi.

Tuy nhiên, những thứ này có xu hướng là các bản dịch theo quy ước và không thể luôn luôn được trình biên dịch kiểm tra. Và bạn có thể vô tình biến một tham chiếu lvalue thành một tham chiếu rvalue bằng cách sử dụng std::move(). Cụ thể, có ba vấn đề:

  • Một tham chiếu có thể tồn tại lâu hơn đối tượng mà nó tham chiếu. Hệ thống trọn đời của Rust ngăn chặn điều này.

  • Có thể có nhiều hơn một tham chiếu có thể thay đổi / không cấu thành bất cứ lúc nào. Công cụ kiểm tra khoản vay của Rust ngăn chặn điều này.

  • Bạn không thể từ chối tham khảo. Bạn không thể nhìn thấy tại một trang web cuộc gọi cho dù chức năng đó tạo ra một tham chiếu đến đối tượng của bạn, mà không biết chữ ký của chức năng được gọi. Do đó, bạn không thể ngăn chặn các tài liệu tham khảo một cách đáng tin cậy, bằng cách xóa bất kỳ phương thức đặc biệt nào của các lớp cũng như bằng cách kiểm tra trang web cuộc gọi để tuân thủ một số hướng dẫn về phong cách không có tài liệu tham khảo.

Vấn đề suốt đời là về an toàn bộ nhớ cơ bản. Tất nhiên việc sử dụng một tham chiếu khi đối tượng được tham chiếu đã hết hạn là bất hợp pháp. Nhưng rất dễ quên về thời gian tồn tại khi bạn lưu trữ một tham chiếu trong một đối tượng, đặc biệt là khi đối tượng đó tồn tại lâu hơn phạm vi hiện tại. Hệ thống loại C ++ không thể giải thích điều này vì nó hoàn toàn không mô hình hóa tuổi thọ đối tượng.

Con std::weak_ptrtrỏ thông minh không mã hóa ngữ nghĩa sở hữu tương tự như một tham chiếu đơn giản, nhưng yêu cầu đối tượng được tham chiếu được quản lý thông qua a shared_ptr, tức là được tính tham chiếu. Đây không phải là một sự trừu tượng chi phí bằng không.

Mặc dù C ++ có hệ thống const, nhưng điều này không theo dõi liệu một đối tượng có thể được sửa đổi hay không, nhưng theo dõi xem một đối tượng có thể được sửa đổi thông qua tham chiếu cụ thể đó hay không . Điều đó không cung cấp đủ sự đảm bảo cho các chương trình đồng thời không sợ hãi. Ngược lại, Rust đảm bảo rằng nếu có một tham chiếu có thể thay đổi hoạt động là tham chiếu duy nhất (thì tôi là người duy nhất có thể thay đổi đối tượng này) và nếu có các tham chiếu không thể thay đổi thì tất cả các tham chiếu đến đối tượng đều không thể thay đổi (Trong khi tôi có thể đọc từ đối tượng, không ai có thể thay đổi nó).

Trong C ++, bạn có thể muốn bảo vệ quyền truy cập vào một đối tượng thông qua một con trỏ thông minh với một mutex. Nhưng như đã thảo luận ở trên một khi chúng ta có một tài liệu tham khảo, nó có thể thoát khỏi tuổi thọ dự kiến ​​của nó. Do đó, một con trỏ thông minh như vậy không thể đảm bảo rằng đó là điểm truy cập duy nhất vào đối tượng được quản lý của nó. Một sơ đồ như vậy thực sự có thể hoạt động trong thực tế bởi vì hầu hết các lập trình viên không muốn phá hoại chính họ, nhưng từ quan điểm kiểu hệ thống, điều này vẫn hoàn toàn không có cơ sở.

Vấn đề chung với con trỏ thông minh là chúng là các thư viện nằm trên ngôn ngữ cốt lõi. Tập hợp các tính năng ngôn ngữ cốt lõi cho phép các con trỏ thông minh này, ví dụ như std::unique_ptrcác nhà xây dựng di chuyển. Nhưng họ không thể sửa chữa thiếu sót trong ngôn ngữ cốt lõi. Các khả năng tạo ngầm định các tham chiếu khi gọi một hàm và có các tham chiếu lơ lửng cùng nhau có nghĩa là ngôn ngữ C ++ cốt lõi là không có cơ sở. Không thể giới hạn các tham chiếu có thể thay đổi thành một tham chiếu duy nhất có nghĩa là C ++ không thể đảm bảo an toàn trước các điều kiện chủng tộc với bất kỳ loại đồng thời nào.

Tất nhiên trong nhiều khía cạnh, C ++ và Rust giống nhau hơn là không giống nhau, đặc biệt là về các khái niệm của chúng về thời gian sống của đối tượng được xác định tĩnh. Nhưng trong khi có thể viết các chương trình C ++ chính xác (miễn là không có lập trình viên nào mắc lỗi), Rust đảm bảo tính chính xác liên quan đến các thuộc tính được thảo luận.


Nếu vấn đề là C ++ không theo dõi quyền sở hữu bằng ngôn ngữ cốt lõi, liệu có thể thực hiện chức năng đó thông qua lập trình meta không? Có nghĩa là bạn sẽ tạo một lớp con trỏ thông minh mới sẽ an toàn cho bộ nhớ bằng cách (1) buộc nó chỉ trỏ đến các đối tượng chỉ sử dụng con trỏ thông minh từ cùng một lớp và (2) theo dõi quyền sở hữu thông qua các mẫu
Elliot Gorokhovsky

2
@ElliotGorokhovsky Không, vì mẫu không thể vô hiệu hóa các tính năng ngôn ngữ cốt lõi như tài liệu tham khảo. Một con trỏ thông minh có thể làm cho việc tham chiếu trở nên khó khăn hơn, nhưng tại thời điểm đó, bạn đang chiến đấu với ngôn ngữ - hầu hết các chức năng thư viện tiêu chuẩn đều cần tham chiếu. Cũng không thể kiểm tra thời gian tồn tại của tài liệu tham khảo thông qua các mẫu vì ngôn ngữ không cung cấp khái niệm thống nhất về thời gian tồn tại.
amon

Tôi hiểu rồi, cảm ơn bạn
Elliot Gorokhovsky
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.