2

押して操作する軽いオブジェクトがいくつかあるので、それらをより複雑なものに含めたいと思います。変更しないままにしておくべきルックアップ テーブルがあります。アイデアは単純に見えますが、これを行う 1 行で --b += c(a);高価な一時ファイルが作成されます。

#include <vector>
static int count;

struct costly {
    /* std::map<std::string, int> and whatnot */
    int b;

    ~costly() { count++; }
     costly(int b): b(b) { }
     costly &operator+= (costly &rhs) { b += rhs.b; return *this; }
};

/* Note the assumption above constructor exists for rhs */
costly operator* (const costly &lhs, costly rhs) {
    rhs.b *= lhs.b; return rhs;
}

struct cheap {
    /* Consider these private or generally unaccessible to 'costly' */
    int index, mul;

    cheap(int index, int mul): index(index), mul(mul) { }
    costly operator() (const std::vector<costly> &rhs) {
        /* Can we do without this? */
        costly tmp = rhs[index] * mul; return tmp;
    }
};

int main(int argc, char* argv[]) {
    std::vector<costly> a = {1, 2}; costly b(1); cheap c = {1, 2};
    /* Above init also calls the destructor, don't care for now */
    count = 0;
    b += c(a);
    return count;
}

私は RVO と C++11 の右辺値について調べてきましたが、導入された中間体を完全に排除するのに十分なほど頭を包むことはできません。上記では、rhs のコンストラクターが使用可能であるため、1 つしか作成しません。最初はこれを持っていました。

costly operator* (costly lhs, int rhs) {
    lhs.b *= rhs; return lhs;
}

/* ... */

costly operator() (const std::vector<costly> &rhs) {
    return rhs[index] * mul;
}

しかし、私の直感に反して、結果はcount2 でさえありました。コンパイラが私の意図を理解していないのはなぜですか?

4

3 に答える 3

1

RVO は関数パラメーターには適用されないため、*オペレーターはそれを禁止しています。RVO を有効にするには、パラメーターのローカル コピーが必要です。次に、右辺値参照を受け取るオーバーロードを提供することで最適化できます (costly効率的な移動コピー コンストラクターがある場合)。例えば、

costly operator*(const costly& c, int i)
{
  costly ret = c;
  ret += 1;
  return ret;
}

costly operator*(costly&& c, int i)
{
  costly ret = std::move(c);
  ret += 1;
  return ret;
}
于 2014-11-16T12:27:06.930 に答える
1

これはまったく異なるアプローチであり、RVO を介して最適化するかどうかとは直交していますが、次のようになります。

コピーを高価にする内部データメンバーは多かれ少なかれ const であるため、その特定のメンバーのコピーを避けるだけではどうですか?

次のように変更した場合costly

struct costly {
    shared_ptr<const map<string, int>> lookup_table;
    int m;
    ...
};

コピーははるかに安くなります。テーブルへのポインターは、それが指すマップが const であっても非 const であることに注意してください。

Sean Parent は、Photoshop で履歴とレイヤーをどのように実装したかについて、これについて非常に良い話をしました。帯域が限られているため、今のところ URL を探すことができません。

于 2014-11-16T14:26:08.153 に答える