2017-06-19 178 views
3

更具體地說,爲什麼doesn'tArc<T>實施from_raw動態大小TBox<T>does是否可以從Vec <T>創建Arc <[T]>?

use std::sync::Arc; 

fn main() { 
    let x = vec![1, 2, 3].into_boxed_slice(); 
    let y = Box::into_raw(x); 
    let z = unsafe { Arc::from_raw(y) }; // ERROR 
} 

play

如在評論中指出,Arc::from_raw必須與來自Arc::into_raw指針所使用的,所以上面的示例中是沒有意義的。我原來的問題(是否有可能從Vec<T>創建一個Arc<[T]>)仍然存在:這是可能的,如果沒有,爲什麼?

+1

也許這是一件好事:如果編譯代碼,它會是UB,因爲'Arc :: from_raw'需要一個由'Arc :: into_raw'返回的指針。儘管如此,'from_raw'需要'T'的部分可能會有很好的答案。 –

+0

@ E_net4真的嗎?然後,寫'let x = Box :: new(5);'而不是在這個例子中是UB? – John

+2

請注意,'Arc :: from_raw()'只能與從'Arc :: into_raw()'返回的值一起使用,因爲'Arc'在數據指針前放置了一個頭部,'Arc :: from_raw'希望找到通過在您提供的指針之前立即查看該標題。 –

回答

7

鐵鏽1.21.0的,你可以這樣做:

let thing: Arc<[i32]> = vec![1, 2, 3].into(); 

這是由RFC 1845啓用:

另外:From<Vec<T>> for Rc<[T]>From<Box<T: ?Sized>> for Rc<T>將增加。

也會爲Arc添加相同的API。

在內部,這uses a method called copy_from_slice,所以Vec的分配不重複使用。有關詳情,請查看DK.'s answer

6

首先,作爲評論已經指出的那樣,你不能折騰原始指針周圍無可奈何地這樣。引用the documentation of Arc::from_raw

原始指針必須先前通過調用Arc::into_raw返回。

你絕對必須閱讀文檔,任何時候你使用的是unsafe方法。

其次,你想要的轉換是不可能的。 Vec<T>Box<[T]>因爲,在內部,Vec<T>實際上是一對(Box<[T]>, usize)。所以,所有的方法都是讓你訪問內部的Box<[T]>指針[1]。然而,Arc<[T]>而不是物理兼容Box<[T]>,因爲它必須包含引用計數。 Arc<T>指向的東西與Box<T>指向的東西具有不同的大小和佈局。

你可以從Vec<T>Arc<[T]>的唯一方法是重新分配引用計數的分配中的向量的內容...我不知道有任何方法要做。我不相信不可能有被實施,它只是沒有[2]。

所有這一切說,我相信不能使用動態大小的類型與Arc::into_raw/Arc::from_raw是一個錯誤。當然可以用動態大小的類型獲得Arc ...雖然只能通過從指針轉換爲固定大小的類型。


[1]:不完全。 Vec<T>不是其實裏面有一個Box<[T]>,但它有一些兼容。它還必須縮小切片以不包含未初始化的元素。

[2]:總的來說,Rust總體上不能很好地支持分配動態大小的東西。特別是這個漏洞的部分原因可能是Box<T>不能直接分配數組,這可能是因爲Vec<T>存在,因爲Vec<T>曾經是語言本身的一部分,爲什麼要添加數組分配到BoxVec已經存在? 「爲什麼不有ArcVec<T>,那?」因爲共享所有權,您永遠無法構造

0

Arc<[T]>是一個Arc,其中包含指向T切片的指針。但[T]實際上並沒有在編譯時確定大小,因爲編譯器不知道它將持續多長時間(與& [T]僅僅是一個參考,因此具有已知大小)。

use std::sync::Arc; 

fn main() { 
    let v: Vec<u32> = vec![1, 2, 3]; 
    let b: Box<[u32]> = v.into_boxed_slice(); 
    let y: Arc<[u32]> = Arc::new(*b); 
    print!("{:?}", y) 
} 

Play Link

然而,你可以使一個Arc<&[T]>未做盒裝片:

use std::sync::Arc; 

fn main() { 
    let v = vec![1, 2, 3]; 
    let y: Arc<&[u32]> = Arc::new(&v[..]); 
    print!("{:?}", y) 
} 

Shared Ref Play Link

然而,這似乎是在與小類型系統研究實用價值。如果你真正想要的是Vec的視圖,你可以在線程之間傳遞,一個Arc將會給你想要的東西。如果你需要它在堆上,Arc<Box<&[T]>>也可以正常工作。