2014-04-28 2 views
3

나는 이것이 무언가 희한한 일임을 알고 있지만 때로는 ffi를 통해 c 라이브러리에 값을 저장 한 다음 c에서 녹 기능에 대한 콜백을 작성하는 것이 도움이되는 경우가 있습니다.안전하지 않은 포인터를 녹여 소유 포인터로 변환 할 수 있습니까?

이런 상황에서 mut * c_void로 저장된 소유 포인터가 있어야하는 상황을 발견했습니다.

이 방법을 forget()과 함께 사용하여 C에 값 을 저장할 수 있으며 상대방에서 mut * T로 비교적 쉽게 부활시킬 수 있지만, 안전하지 않은 포인터와 다시이 상황에서 '안전한'녹 공간으로.

그러나 컴파일러는 & 포인터에서 참조를 이동하는 것에 대해 항상 불만을 토로합니다.

& T 또는 * T를 unsafe로 ~ T로 변환하려면 특별한 방법이 있습니까? 조금 불분명 할 수있다

, 그래서 여기에 구체적인 예입니다 :

extern crate libc; 

use libc::c_void; 
use std::ops::Drop; 
use std::intrinsics::forget; 

struct Foo { x: int } 

impl Drop for Foo { 
    fn drop(&mut self) { 
    println!("We discarded our foo thanks!"); 
    } 
} 

fn main() { 
    let mut x = ~Foo { x: 10 }; 

    let mut y = & mut *x as * mut Foo; 
    println!("Address Y: {:x}", y as uint); 

    let mut z = y as * mut c_void; 
    println!("Address Z: {:x}", z as uint); 

    // Forget x so we don't worry about it 
    unsafe { forget(x); } 

    // This would normally happen inside the ffi callback where 
    // the ffi code discards the void * it was holding and returns it. 
    unsafe { 
    let mut res_z = z as * mut Foo; 
    println!("Ressurected Z: {:x}", z as uint); 

    let mut res_y = & mut (*res_z); 
    println!("Ressurected Y: {:x}", y as uint); 

    let mut res_x:~Foo = ~(*res_y); 
    } 
} 

때문에 마지막 줄은 컴파일되지 않을 것이다 : 당신은 소멸자가 호출되지 않습니다 그 라인을 제거하면

test.rs:34:28: 34:34 error: cannot move out of dereference of `&mut`-pointer 
test.rs:34  let mut res_x:~Foo = ~(*res_y); 

; 그 메모리 블록을 다시 '안전한'녹 영역으로 옮기고 블록 범위가 끝나면 올바르게 모으는 방법을 찾고 있습니다.

편집 : 나는 swap()이 이것을 수행하는 방법으로 생각합니다. 그러나 누출없이 올바르게 수행하는 정확한 의미는 여전히 조금 불분명합니다. 예를 들어, https://gist.github.com/shadowmint/11361488 ~ ~ Foo leaks; 소멸자는 잊혀진 ~ Foo에 대해 호출되지만 대신 tmp에서 생성 된 로컬 ~ Foo가 누설됩니다. :/

답변

2

귀하의 오류가 발생합니다. 소유 포인터를 만들면 항상 힙에 대한 할당을 의미하므로 소유 포인터를 무언가에 "가져갈"수 없습니다. 따라서 ~ 오류는 &mut 값을 이동하려고 시도합니다. 허용되지 않습니다.

나는 정말 안전하지 않은 것 같은 종류의 당신이 cast::transmute()을해야한다는 생각이 수정과

use std::cast; 

// ... 

let mut res_x: ~Foo = cast::transmute(res_y); 

코드는 잘 작동하며 We discarded our foo thanks!를 인쇄합니다. 그러나 을 실제로으로 확인하면 cast::transmute()과 완전히 일치하지 않으므로 (변환 된 유형의 메모리 크기 제외) 모든 것을 모두 캐스팅 할 수 있기 때문에주의해야합니다.

+0

그게 바로 제가 고맙다고 생각한 것입니다 ~ – Doug

0

구문이 올바른가요? 내가 틀리지 않으면 선은 아래처럼 보일 것입니다.

let mut res_x:~Foo = (*res_y); 

나는 녹하는 초보자 그리고 난 그냥이 [링크] 다음 : ~ 포인터를 복용하지, 권투에 대한 연산자이기 때문에 http://cmr.github.io/blog/2013/08/13/rust-by-concept/

+0

그렇지 않으면 외부에서 액세스 할 수있는 res_y의 소멸자를 호출하는 데 하나 이상의 함수를 작성해야한다고 생각합니다. – santu47

+0

이 경우 res_y는 & mut T이며,이를 ~ T로 '승격'하고 싶습니다. * res_y는 실제로 T가 될 것이지만, 어떻게 든 소유 된 포인터로 변환하려고합니다. – Doug

관련 문제