3

コンピュータはデータをコピーしているのではなく、データのアドレスを指しているだけなので、参照渡しは値渡しよりも高速である必要があると思いました。

ただし、次の C++ コードを検討してください。

#include <iostream>
#include <cassert>
#include <cmath>

using namespace std;

// do not use pass by reference& with this function, it will become so slow
unsigned long long computePascal(const unsigned int row, const unsigned int position) {
    if (position == 1 || position == row)
    return 1L;
    unsigned long long left = computePascal(row-1, position-1);
    unsigned long long right = computePascal(row-1, position);
    unsigned long long sum = left + right;
    return sum;
}

int main() {
    int row, position;
    cout << "Input row and position: ";
    cin >> row >> position;
    assert(position > 0 && position <= row);
    unsigned long long pascalNumber = computePascal(row, position);
    cout << pascalNumber << endl;
    return 0;
}

現在、このコードは、三角形の目的の行と位置を入力してパスカル数を再帰的に計算する通常のプログラムです。

行50と位置7を入れてみましたが、約1秒で計算されます(値渡し)。出力は約 1300 万です。これは正しい値です。大量のデータをコピーする必要がないので、代わりに参照渡しをした方が高速になるのではないかと考えました。しかし、これは非常に間違っており、値渡しにかかった時間の約 3 倍の時間がかかった理由がわかりません。質問は ...

const 参照で渡すように変更しようとすると、このプログラムの計算が遅くなるのはなぜですか?

再帰関数は例外であるため、const 参照ではなく値で渡す必要がありますか?

4

1 に答える 1

15

「どちらが速いか」に対する答えは、通常「場合による」です。

4 バイトのデータを渡す代わりに、データへの 8 バイトのポインタを渡している場合、処理が高速になるとは期待できません。100 バイトのデータを渡す代わりに、データへの 8 バイトのポインターを渡す場合、それは異なります。

しかし、関数にはデータがなく、参照しかありません。したがって、データを読み取る必要があるときはいつでも、参照を介して間接的に行う必要があります。それには時間がかかります。100 バイトのオブジェクトを渡して 8 バイトしか読み取らない場合でも、勝つ可能性は高くなります。しかし、実際にすべてのデータを、場合によっては複数回読み取った場合は、大きなオブジェクトであっても、値を渡す方が簡単に高速になる可能性があります。

本当の違いは、オブジェクトを渡すときに発生し、値で渡すことは、多かれ少なかれ複雑なコンストラクターが呼び出されることを意味します。参照渡しとは、コンストラクタがないことを意味します。しかし、とにかく int にはコンストラクターがありません。

そして、最適化があります。値渡しとは、関数がデータにアクセスできる唯一の関数であることをコンパイラが認識していることを意味します。参照渡しとは、データがどこにでもある可能性があることを意味します。int& パラメータが 2 つある場合、int を 2 回渡すことができます。したがって、行を増やすと、posが増える可能性があります。またはそうではないかもしれません。それは最適化を殺します。

そして、最適化のルールがあります:「測定する」。あなたはそれを測定し、より速いものを見つけました。正当な理由もなく、物事が速くなったり遅くなったりすることがあります。

于 2014-10-24T16:57:30.293 に答える