mungkin untuk mencapai model kepemilikan Rust dengan bungkus C ++ generik?


15

Melihat melalui artikel ini tentang keamanan konkurensi Rust:

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

Saya bertanya-tanya berapa banyak dari ide-ide ini dapat dicapai di C ++ 11 (atau lebih baru). Secara khusus dapatkah saya membuat kelas pemilik yang mentransfer kepemilikan ke metode apa pun yang dapat dilewati? Tampaknya C ++ memiliki begitu banyak cara untuk melewatkan variabel sehingga tidak mungkin, tetapi mungkin saya bisa memberikan beberapa batasan pada kelas atau templat untuk memastikan bahwa beberapa kode templat dijalankan dengan setiap metode yang dilewati?


Beberapa kutipan dari tautan akan meningkatkan pertanyaan ini
Martin Ba

2
@delnan (Aman) Rust menjamin bahwa Anda tidak pernah memiliki lebih dari satu referensi yang bisa berubah untuk sesuatu pada suatu waktu dan bahwa Anda tidak pernah memiliki referensi yang bisa berubah untuk hal yang juga Anda miliki referensi baca-saja. Ini juga memiliki beberapa batasan dalam mentransfer data di antara utas. Bersama-sama ini mencegah kelas signifikan terkait threading bug dan membuat alasan tentang keadaan objek lebih mudah, bahkan dalam kode berulir tunggal.
CodesInChaos

3
Anda tidak berpikir Anda dapat mengekspresikan pinjaman dengan cara yang dapat diverifikasi oleh kompiler C ++, jadi Anda harus menggunakan penegakan runtime dengan hit kinerja terkait.
CodesInChaos

1
Bukankah kepemilikan lingkup sudah diterapkan oleh smart pointer di C ++ 11?
Akshat Mahajan

1
@JerryJeremiah Rust memiliki berbagai jenis referensi. Yang dasar,, &tidak memerlukan promosi untuk digunakan. Jika Anda mencoba untuk mendapatkan &mutsementara Anda masih punya referensi lain (bisa berubah atau tidak) untuk item yang sama, Anda tidak akan dapat mengkompilasi. RefCell<T>memindahkan tanda centang untuk menjalankan waktu, jadi Anda akan panik jika mencoba .borrow_mut()sesuatu yang sudah aktif .borrow()atau .borrow_mut(). Rust juga memiliki Rc<T>(berbagi memiliki penunjuk) dan saudara kandungnya Weak<T>, tetapi itu adalah tentang kepemilikan, bukan mutabilitas. Tempelkan RefCell<T>bagian dalamnya untuk berubah-ubah.
8bittree

Jawaban:


8

C ++ memiliki tiga cara untuk meneruskan parameter ke fungsi: dengan nilai, dengan referensi nilai, dan dengan referensi nilai. Dari jumlah tersebut, melewati nilai menciptakan kepemilikan dalam arti bahwa fungsi yang dipanggil menerima salinannya sendiri, dan memberikan referensi nilai menunjukkan bahwa nilai tersebut dapat dikonsumsi, yaitu tidak akan lagi digunakan oleh pemanggil. Melewati dengan referensi nilai berarti bahwa objek tersebut sementara dipinjam dari pemanggil.

Namun, ini cenderung “berdasarkan kesepakatan” dan tidak selalu dapat diperiksa oleh kompiler. Dan Anda dapat secara tidak sengaja mengubah referensi nilai menjadi referensi nilai menggunakan std::move(). Secara konkret, ada tiga masalah:

  • Referensi dapat hidup lebih lama dari objek yang dirujuk. Sistem seumur hidup Rust mencegah hal ini.

  • Mungkin ada lebih dari satu referensi yang bisa berubah / non-const aktif kapan saja. Pemeriksa pinjaman Rust mencegah hal ini.

  • Anda tidak dapat menyisih dari referensi. Anda tidak dapat melihat di situs panggilan apakah fungsi itu membuat referensi ke objek Anda, tanpa mengetahui tanda tangan dari fungsi yang dipanggil. Oleh karena itu Anda tidak dapat secara andal mencegah referensi, baik dengan menghapus metode khusus kelas Anda maupun dengan mengaudit situs panggilan untuk kepatuhan dengan beberapa panduan gaya "tanpa referensi".

Masalah seumur hidup adalah tentang keamanan memori dasar. Tentu saja ilegal menggunakan referensi ketika objek yang dirujuk telah kedaluwarsa. Tetapi sangat mudah untuk melupakan masa hidup ketika Anda menyimpan referensi dalam suatu objek, khususnya ketika objek itu hidup lebih lama dari ruang lingkup saat ini. Sistem tipe C ++ tidak dapat menjelaskan hal ini karena sama sekali tidak memodelkan objek seumur hidup.

The std::weak_ptrpointer pintar tidak semantik kepemilikan encode mirip dengan referensi polos, tetapi membutuhkan bahwa objek direferensikan dikelola melalui shared_ptr, yaitu adalah referensi-dihitung. Ini bukan abstraksi tanpa biaya.

Sementara C ++ memiliki sistem const, ini tidak melacak apakah suatu objek dapat dimodifikasi, tetapi melacak apakah suatu objek dapat dimodifikasi melalui referensi tertentu . Itu tidak memberikan jaminan yang cukup untuk "konkurensi tanpa rasa takut". Sebaliknya, Rust menjamin bahwa jika ada referensi yang bisa berubah aktif yang merupakan satu-satunya referensi ("Saya adalah satu-satunya yang dapat mengubah objek ini") dan jika ada referensi yang tidak bisa diubah maka semua referensi ke objek tidak dapat diubah ("Selagi aku bisa membaca dari objek, tidak ada yang bisa mengubahnya").

Di C ++ Anda mungkin tergoda untuk menjaga akses ke objek melalui penunjuk pintar dengan mutex. Tetapi seperti yang telah dibahas di atas begitu kita memiliki referensi, ia dapat lolos dari umur yang diharapkan. Oleh karena itu penunjuk pintar semacam itu tidak dapat menjamin bahwa itu adalah satu-satunya titik akses ke objek yang dikelola. Skema seperti itu mungkin benar-benar berhasil dalam praktik karena sebagian besar programmer tidak ingin menyabot diri mereka sendiri, tetapi dari sudut pandang tipe sistem ini masih sepenuhnya tidak sehat.

Masalah umum dengan pointer cerdas adalah bahwa mereka adalah perpustakaan di atas bahasa inti. Seperangkat fitur bahasa inti memungkinkan pointer cerdas ini, mis. std::unique_ptrKebutuhan pemindah-konstruktor. Tetapi mereka tidak dapat memperbaiki kekurangan dalam bahasa inti. Kemampuan untuk secara implisit membuat referensi ketika memanggil suatu fungsi dan untuk menggantung referensi bersama berarti bahwa bahasa inti C ++ tidak sehat. Ketidakmampuan untuk membatasi referensi yang dapat diubah menjadi satu berarti bahwa C ++ tidak dapat menjamin keamanan terhadap kondisi balapan dengan segala jenis konkurensi.

Tentu saja dalam banyak hal C ++ dan Rust lebih mirip daripada disalike, khususnya mengenai konsep-konsep mereka tentang kehidupan objek yang ditentukan secara statis. Tetapi sementara dimungkinkan untuk menulis program C ++ yang benar (asalkan tidak ada programmer yang melakukan kesalahan), Rust menjamin kebenaran mengenai properti yang dibahas.


Jika masalahnya adalah bahwa C ++ tidak melacak kepemilikan dalam bahasa inti, apakah mungkin untuk mengimplementasikan fungsi itu melalui meta-programming? Berarti Anda akan membuat kelas penunjuk cerdas baru yang akan aman memori dengan (1) memaksanya untuk menunjuk secara eksklusif ke objek yang hanya menggunakan penunjuk pintar dari kelas yang sama dan (2) melacak kepemilikan melalui templat
Elliot Gorokhovsky

2
@ElliotGorokhovsky Tidak, karena templat tidak dapat menonaktifkan fitur bahasa inti seperti referensi. Pointer pintar dapat membuatnya lebih sulit untuk mendapatkan referensi, tetapi pada saat itu Anda memperjuangkan bahasa - sebagian besar fungsi perpustakaan standar membutuhkan referensi. Juga tidak mungkin untuk memeriksa masa berlaku referensi melalui templat karena bahasa tersebut tidak menawarkan konsep seumur hidup yang direvisi.
amon

Saya mengerti, terima kasih
Elliot Gorokhovsky
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.