Zero-SizedなオブジェクトをVecに入れてみる
Zero-Sizedなオブジェクトは、メンバを持たない構造体から作ることができます。
struct Blank; // struct Blank {} と同じ fn main() { println!("{}", std::mem::size_of::<Blank>()); // => 0 }
ちなみに、メンバを持たないenumもサイズは0です
enum BlankEnum; fn main() { println!("{}", std::mem::size_of::<BlankEnum>()); // => 0 }
(が、メンバがないのでenumからZero-Sizedのオブジェクトを作り出すことはできません)
ちなみに②、
上記の通りenumのサイズはメンバの"数"によってきまり、
メンバが1個なら0 byte,
1~256個なら1,
257~多分65536個なら2,
.
.
.
となります(なるはずです)
enum A { Member1, Member2, ... Member256 } enum B { Member1, Member2, ... Member256, Member257 } fn main() { println!("{}", std::mem::size_of::<A>()); // => 1 println!("{}", std::mem::size_of::<B>()); // => 2 }
(一応断っておくと、すべてがデータを持たないenumの場合の話です)
さて話は戻って、
Vec
からなる構造体なので、
ここにZeroSizedなオブジェクトを入れたらどうなるのだろうと、やってみました
ちなみに③、
0サイズのオブジェクトでもアロケーションはされている(と言ってよいのだろうか)ようです
struct Blank; fn main() { let obj_in_vain = Blank{}; println!("{:?}", &obj_in_vain as *const Blank); // => <なんらかのアドレスが印字される> }
さて、今度こそVecにZeroSizedなオブジェクトをいれていきます
struct Blank; fn main() { let mut blank_vec = Vec::<Blank>::new(); blank_vec.push(Blank{}); blank_vec.push(Blank{}); blank_vec.push(Blank{}); println!("length: {}", blank_vec.len()); // length: 3 println!("capacity: {}", blank_vec.capacity()); // capacity: 18446744073709551615 println!("ptr: {:?}", blank_vec.as_ptr()); // ptr: 0x1 }
長さは普通です。
キャパシティは18446744073709551615と std::usize::MAX_VALUEが返ってますね。
これはここの実装によりそうです。
そもそもサイズが0のものは理論上無限に詰め込んでよいはずなので、usizeの最大値が返るのはなんとなくわかる話です。
そしてポインタですが、 0x1
になっています。
空のオブジェクトはアロケーションされても、空のオブジェクトのVecはどこも指さないんですね。
勉強になりました。
ちなみに④、
なぜ 0x0
でなく 0x1
なのかというと、
参照はNonZeroだからのような気がします。
nullポインタ最適化ってやつのためでしょうか。
struct Blank; fn main() { println!("{}", std::mem::size_of::<usize>()); println!("{}", std::mem::size_of::<Option<usize>>()); println!("{}", std::mem::size_of::<&usize>()); println!("{}", std::mem::size_of::<Option<&usize>>()); // なんと増えない }
Rustおもしろいですね。