일반적인 C ++ 래퍼로 Rust의 소유권 모델을 달성 할 수 있습니까?


15

Rust의 동시성 안전에 대한이 기사를 살펴보면 :

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

나는 C ++ 11 (또는 그 이상)에서 얼마나 많은 아이디어를 얻을 수 있는지 궁금합니다. 특히 소유권을 전달할 수있는 메소드로 소유권을 이전하는 소유자 클래스를 작성할 수 있습니까? C ++에는 변수를 전달하는 방법이 너무 많기 때문에 불가능할 수도 있지만 클래스 또는 템플릿에 일부 제한 사항을 적용하여 모든 메서드 패스와 함께 일부 템플릿 코드가 실행되도록 할 수 있습니까?


링크에서 인용 한 일부 인용문은이 질문을 개선 할 것입니다
— Martin Ba

2
@delnan (Safe) Rust는 한 번에 하나 이상의 변경 가능한 참조가없고 읽기 전용 참조가있는 것에 대한 변경 가능한 참조가 없음을 보장합니다. 또한 스레드 간 데이터 전송에 대한 일부 제한 사항이 있습니다. 이것들은 함께 스레딩 관련 버그의 중요한 클래스를 방지하고 단일 스레드 코드에서도 객체 상태에 대한 추론을 더 쉽게 만듭니다.
— 코드 InChaos

3
C ++ 컴파일러가 확인할 수있는 방식으로 차용을 표현할 수 있다고 생각하지 않으므로 관련 성능 저하로 런타임 시행을 사용해야합니다.
— 코드 InChaos

1
C ++ 11에서 스마트 포인터로 이미 구현 된 소유권을 다루지 않습니까?
— Akshat Mahajan

1
@JerryJeremiah Rust에는 다양한 참조 유형이 있습니다. 기본 광고 &는 어떤 종류의 프로모션도 필요하지 않습니다. 당신이 얻을하려고하면 &mut당신은 여전히 같은 항목에 대한 다른 참조 (변경 가능 여부)를 가지고있는 동안, 당신은 컴파일 할 수 없습니다. RefCell<T>당신이하려고하면 당신이 공포를 얻을 수 있습니다 있도록 이동 체크는, 시간을 실행하는 .borrow_mut()이미 활성 가지고 무언가 .borrow()또는 .borrow_mut(). Rust는 또한 Rc<T>(공유 소유 포인터)와 그 형제 Weak<T>를 가지고 있지만 그것들은 변경이 아닌 소유권에 관한 것입니다. 스틱 RefCell<T>가변성 그들 내부.
— 8bittree

답변:


8

C ++에는 매개 변수를 함수에 전달하는 세 가지 방법이 있습니다 : 값, lvalue 참조 및 rvalue 참조. 이 중에서 값을 전달하면 호출 된 함수가 자체 사본을 수신한다는 의미에서 소유권을 생성하고 rvalue 참조를 전달하면 값이 소비 될 수 있음을 나타냅니다. 즉, 더 이상 호출자가 사용하지 않습니다. lvalue 참조로 전달하면 오브젝트가 호출자로부터 일시적으로 차용되었음을 의미합니다.

그러나 이러한 규칙은 "규칙에 따른"경향이 있으며 컴파일러가 항상 확인할 수는 없습니다. 그리고 실수로을 사용하여 lvalue 참조를 rvalue 참조로 바꿀 수 있습니다 std::move(). 구체적으로 세 가지 문제가 있습니다.

  • 참조는 참조하는 객체보다 오래 지속될 수 있습니다. 녹의 평생 시스템은 이것을 방지합니다.

  • 언제든지 하나 이상의 변경 가능 / 비 Const 기준이 활성화 될 수 있습니다. Rust의 빌림 검사기는 이것을 방지합니다.

  • 참조를 선택 해제 할 수 없습니다. 호출 된 함수의 서명을 모르면 해당 함수가 객체에 대한 참조를 생성하는지 여부를 콜 사이트에서 확인할 수 없습니다. 따라서 클래스의 특수 메소드를 삭제하거나 일부 "참조 없음"스타일 안내서를 준수하는지 콜 사이트를 감사하여 참조를 확실하게 막을 수 없습니다.

수명 문제는 기본 메모리 안전에 관한 것입니다. 물론 참조 된 객체가 만료되었을 때 참조를 사용하는 것은 불법입니다. 그러나 객체 내에 참조를 저장할 때, 특히 해당 객체가 현재 범위보다 오래 지속되는 수명을 잊어 버리는 것은 매우 쉽습니다. C ++ 타입 시스템은 객체 수명을 전혀 모델링하지 않기 때문에 이것을 설명 할 수 없습니다.

std::weak_ptr스마트 포인터는 일반 기준과 유사한 인코딩 소유권 의미를 수행하지만, 참조 된 개체가를 통해 관리 될 것을 요구 shared_ptr, 즉 참조 카운트입니다. 이것은 비용이 들지 않는 추상화가 아닙니다.

C ++에는 const 시스템이 있지만 객체를 수정할 수 있는지 여부는 추적하지 않지만 해당 특정 참조를 통해 객체를 수정할 수 있는지 여부를 추적합니다 . "무서 한 동시성"에 대한 충분한 보장을 제공하지 않습니다. 반대로 Rust는 유일한 참조 인 (“이 오브젝트를 변경할 수있는 유일한 사람입니다”) 활성 변경 가능한 참조가 있고 변경 불가능한 참조가있는 경우 해당 오브젝트에 대한 모든 참조는 변경할 수 없습니다 ( "객체에서 읽을 수는 있지만 아무도 변경할 수 없습니다").

C ++에서는 뮤텍스가있는 스마트 포인터를 통해 객체에 대한 액세스를 보호하려는 유혹을받을 수 있습니다. 그러나 위에서 언급했듯이 참조가 있으면 예상 수명을 벗어날 수 있습니다. 따라서 이러한 스마트 포인터는 관리 대상 개체에 대한 단일 액세스 지점임을 보장 할 수 없습니다. 이러한 계획은 실제로 대부분의 프로그래머가 스스로 방해하기를 원하지 않기 때문에 실제로 작동 할 수 있지만 유형 시스템 관점에서 볼 때 이것은 여전히 ​​완전하지 않습니다.

스마트 포인터의 일반적인 문제점은 핵심 언어 위에있는 라이브러리라는 것입니다. 핵심 언어 기능 세트는 이러한 스마트 포인터를 가능하게합니다 (예 : std::unique_ptr이동 생성자 필요). 그러나 핵심 언어 내에서 결함을 수정할 수는 없습니다. 함수를 호출 할 때 암시 적으로 참조를 작성하고 함께 참조를 매달려있는 기능은 핵심 C ++ 언어가 적절하지 않다는 것을 의미합니다. 변경 가능한 참조를 단일 참조로 제한 할 수 없다는 것은 C ++이 모든 종류의 동시성으로 경쟁 조건에 대한 안전을 보장 할 수 없음을 의미합니다.

물론 많은 측면에서, C ++과 Rust는 특히 정적으로 결정된 객체 수명 개념에 대해 싫어하는 것보다 더 비슷합니다. 그 동안 그러나 수 (프로그래머의 제공 아무도 실수를하지 않습니다) 올바른 C ++ 프로그램을 작성, 녹 보장 논의 된 속성에 대한 정확성.


문제가 C ++이 핵심 언어의 소유권을 추적하지 못한다면 메타 프로그래밍을 통해 해당 기능을 구현할 수 있습니까? 즉, (1) 동일한 클래스의 스마트 포인터 만 사용하는 객체 만 가리키고 (2) 템플릿을 통한 소유권 추적
— Elliot Gorokhovsky

2
@ElliotGorokhovsky 아니요. 템플릿은 참조와 같은 핵심 언어 기능을 비활성화 할 수 없기 때문입니다. 스마트 포인터는 참조를 얻기가 더 어려울 수 있지만 그 시점에서 언어와 싸우고 있습니다. 대부분의 표준 라이브러리 함수에는 참조가 필요합니다. 언어가 통일 된 개념의 수명을 제공하지 않기 때문에 템플릿을 통해 참조의 수명을 확인할 수도 없습니다.
— amon

감사합니다
— Elliot Gorokhovsky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.