2017-06-19 2 views
3

Um genauer zu sein, warum doesn'tArc<T> implementieren from_raw mit einer dynamisch Größe T während Box<T>does?Ist es möglich, einen Arc <[T]> von einem Vec <T> zu erstellen?

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)

Wie in den Kommentaren darauf hingewiesen, Arc::from_rawmuss mit einem Zeiger von Arc::into_raw verwendet werden, so dass das obige Beispiel nicht sinnvoll. Meine ursprüngliche Frage (Ist es möglich, ein Arc<[T]> von einem Vec<T> zu erstellen) bleibt: ist das möglich, und wenn nicht, warum?

+1

Vielleicht ist das eine gute Sache: Es wäre UB gewesen, wenn dieser Code kompiliert würde, weil 'Arc :: from_raw' einen Zeiger erwartet, der von' Arc :: into_raw' zurückgegeben wird. Nichtsdestoweniger könnte der Teil, bei dem 'from_raw'' T' benötigt, eine gute Antwort haben. –

+0

@ E_net4 Wirklich? Dann schreiben wir "let x = Box :: new (5);" anstatt im Beispiel wäre UB? – John

+2

Beachten Sie, dass 'Arc :: from_raw()' nur mit einem Wert verwendet werden darf, der von 'Arc :: in_raw()' zurückgegeben wird, weil 'Arc' einen Header vor dem Datenzeiger platziert und' Arc :: from_raw' erwartet diesen Header, indem Sie direkt vor dem von Ihnen angegebenen Zeiger suchen. –

Antwort

7

Ab Rust 1.21.0, können Sie dies tun:

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

Das von RFC 1845 aktiviert wurde:

Zusätzlich: From<Vec<T>> for Rc<[T]> und From<Box<T: ?Sized>> for Rc<T> wird hinzugefügt.

Identische APIs werden auch für Arc hinzugefügt.

Intern dies uses a method called copy_from_slice, so dass die Zuordnung der Vec nicht wiederverwendet werden. Für die Details warum, überprüfen Sie DK.'s answer.

6

Nr

Zunächst einmal, wie schon in den Kommentaren erwähnt, können Sie rund um rohe Zeiger werfen nicht wohl oder übel so. Zitieren the documentation of Arc::from_raw:

Der Rohzeiger zuvor durch einen Aufruf von einem Arc::into_raw zurück müssen.

Sie unbedingt müssen lesen Sie die Dokumentation jederzeit Sie ein unsafe Methode verwenden.

Zweitens ist die Konvertierung, die Sie wollen, unmöglich. Vec<T>Box<[T]> funktioniert, weil intern Vec<T> effektiv ein (Box<[T]>, usize) Paar ist. Also gibt Ihnen die ganze Methode Zugriff auf den internen Zeiger Box<[T]> [1]. Arc<[T]> ist jedoch nicht physikalisch kompatibel mit einem Box<[T]>, weil es die Referenzzählungen enthalten muss. Die Sache, auf die durch Arc<T> gezeigt wird, weist eine andere Größe und ein anderes Layout auf, auf das durch Box<T> hingewiesen wird.

Die einzige Möglichkeit, die Sie von Vec<T> bis Arc<[T]> erhalten, wäre die Neuzuordnung des Inhalts des Vektors in einer Referenz-gezählten Zuweisung ... was mir nicht bekannt ist. Ich glaube nicht, dass es einen bestimmten Grund gibt es konnte nicht umgesetzt werden, es hat einfach nicht [2].

Alles, was gesagt, ich glaube, nicht in der Lage, dynamisch große Typen mit Arc::into_raw/ ist ein Fehler. Es ist sicherlich möglich, Arc s mit dynamisch großen Typen zu erhalten ... aber nur durch das Umwandeln von Zeigern in Typen mit fester Größe.


[1]: Nicht ganz. Vec<T> nicht eigentlich haben eine Box<[T]> drin, aber es hat etwas kompatibel. Außerdem muss das Segment verkleinert werden, damit es keine nicht initialisierten Elemente enthält.

[2]: Rust hat im Großen und Ganzen keine gute Unterstützung für die Zuweisung von dynamisch großen Dingen im Allgemeinen.Es ist möglich, dass ein Teil des Grundes für dieses Loch insbesondere ist, dass Box<T>auch Arrays nicht direkt zuordnen kann, was möglicherweise, weil Vec<T> existiert, weil Vec<T> verwendet wurde, um Teil der Sprache selbst zu sein, und warum würden Sie Array-Zuweisung hinzufügen zu Box wenn Vec bereits existiert? "Warum nicht ArcVec<T>, dann?" Weil Sie nie konstruieren könnten eins aufgrund der gemeinsamen Besitz.

0

Arc<[T]> ist ein Arc enthält einen Zeiger auf eine Scheibe von T 's. Aber [T] wird nicht wirklich zur Kompilierzeit Größe, da der Compiler nicht weiß, wie lange es sein wird (im Gegensatz & [T], die nur eine Referenz ist und somit eine bekannte Größe hat).

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

Sie können jedoch einen Arc<&[T]> machen, ohne einen Boxed Scheibe zu machen:

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

Allerdings scheint dies wie eine Studie in der Art System mit wenig praktischer Wert. Wenn das, was Sie wirklich wollen, eine Ansicht des Vec ist, die Sie zwischen Threads weitergeben können, wird Ihnen ein Arc < & [T]> geben, was Sie wollen. Und wenn Sie es auf dem Haufen benötigen, funktioniert Arc<Box<&[T]>> auch gut.

Verwandte Themen