일반적인 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.