if (i < input.size() - 1) print(0);
このループで最適化されinput.size()
、すべての反復で読み取られるわけではない同僚に私は主張しましたが、これはそうではありません!
void print(int x) {
std::cout << x << std::endl;
}
void print_list(const std::vector<int>& input) {
int i = 0;
for (size_t i = 0; i < input.size(); i++) {
print(input[i]);
if (i < input.size() - 1) print(0);
}
}
gccオプション付きのコンパイラエクスプローラによると、-O3 -fno-exceptions
実際にはinput.size()
各反復を読み取りlea
、減算を実行するために使用しています。
movq 0(%rbp), %rdx
movq 8(%rbp), %rax
subq %rdx, %rax
sarq $2, %rax
leaq -1(%rax), %rcx
cmpq %rbx, %rcx
ja .L35
addq $1, %rbx
興味深いことに、Rustではこの最適化が行われます。反復ごとに減分さi
れる変数に置き換えられたように見えj
、テストi < input.size() - 1
はのようなものに置き換えられj > 0
ます。
fn print(x: i32) {
println!("{}", x);
}
pub fn print_list(xs: &Vec<i32>) {
for (i, x) in xs.iter().enumerate() {
print(*x);
if i < xs.len() - 1 {
print(0);
}
}
}
ではコンパイラエクスプローラの関連アセンブリは、次のようになります。
cmpq %r12, %rbx
jae .LBB0_4
私はチェックしましたが、カウンターでr12
あるxs.len() - 1
と確信していrbx
ます 以前は、add
for rbx
とmov
のループの外側にありますr12
。
どうしてこれなの?これは、GCCはインライン展開することができる場合のように思えるsize()
し、operator[]
それがなかったとして、それは知っていることができるはずsize()
は変更されません。しかし、GCCのオプティマイザが変数に引き出す価値はないと判断したのでしょうか?あるいは、これを安全でないものにする可能性のある他のいくつかの副作用があるかもしれません-誰か知っていますか?
cout.operator<<()
です。コンパイラーは、このブラックボックス関数がstd::vector
グローバルからの参照を取得しないことを知りません。
println
またはの複雑さoperator<<
が重要であるとあなたは正しいです。
println
、おそらく複雑な方法であり、コンパイラーはprintln
ベクトルを変更しないことを証明できない場合があります。