3

他の計算に必要な「スクラッチパッド」である C++ データ構造があります。寿命が短く、頻繁に使用されるわけではないため、パフォーマンスは重要ではありません。ただし、他の更新可能な追跡フィールドの中に乱数ジェネレーターが含まれており、ジェネレーターの実際の値は重要ではありませんが、コピーして再利用するのではなく、値を更新する ことが重要です。これは、一般に、このクラスのオブジェクトは参照によって渡されることを意味します。

インスタンスが 1 回だけ必要な場合、最も自然な方法は、必要に応じてインスタンスを作成し (おそらくファクトリ メソッドまたはコンストラクターを使用)、スクラッチパッドを消費するメソッドに渡すことです。コンシューマーのメソッド シグネチャは、これが唯一の用途であることを知らないため、参照渡しを使用しますが、ファクトリ メソッドとコンストラクターは値渡しで返されます。また、名前のない一時オブジェクトを参照渡しすることはできません。

厄介な一時変数でコードが詰まらないようにする方法はありますか? 次のようなことは避けたいです。

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
xyz.initialize_computation(useless_temp);

スクラッチパッドを本質的に作成し、mutableすべてのパラメーターにラベルを付けるだけで済みますconst &が、誤解を招く可能性があるため、ベストプラクティスとは言えません。完全に制御できないクラスに対してはこれを行うことはできません。右辺値参照で渡すには、スクラッチパッドのすべてのコンシューマーにオーバーロードを追加する必要があります。これは、明確で簡潔なコードを持つという目的に反します。

パフォーマンスは重要ではないという事実 (ただし、コード サイズと可読性は重要) を考えると、そのようなスクラッチパッドを渡すためのベスト プラクティスのアプローチは何ですか? 必要に応じて C++0x の機能を使用しても問題ありませが、できれば C++03 のみの機能で十分です。

編集: 明確にするために、一時的なものを使用することは可能です。それは、私が避けたいコードの残念な混乱です。一時的に名前を付けない場合、それは明らかに 1 回しか使用されず、読み取るコードの行数が少ないほど優れています。また、コンストラクターの初期化子では、一時変数を宣言することはできません。

4

5 に答える 5

4

While it is not okay to pass rvalues to functions accepting non-const references, it is okay to call member functions on rvalues, but the member function does not know how it was called. If you return a reference to the current object, you can convert rvalues to lvalues:

class scratchpad_t
{
    // ...

public:

    scratchpad_t& self()
    {
        return *this;
    }
};

void foo(scratchpad_t& r)
{
}

int main()
{
    foo(scratchpad_t().self());
}

Note how the call to self() yields an lvalue expression even though scratchpad_t is an rvalue.

Please correct me if I'm wrong, but Rvalue reference parameters don't accept lvalue references so using them would require adding overloads to all consumers of scratchpad, which is also unfortunate.

Well, you could use templates...

template <typename Scratch> void foo(Scratch&& scratchpad)
{
    // ...
}

If you call foo with an rvalue parameter, Scratch will be deduced to scratchpad_t, and thus Scratch&& will be scratchpad_t&&.

And if you call foo with an lvalue parameter, Scratch will be deduced to scratchpad_t&, and because of reference collapsing rules, Scratch&& will also be scratchpad_t&.

Note that the formal parameter scratchpad is a name and thus an lvalue, no matter if its type is an lvalue reference or an rvalue reference. If you want to pass scratchpad on to other functions, you don't need the template trick for those functions anymore, just use an lvalue reference parameter.

By the way, you do realize that the temporary scratchpad involved in xyz.initialize_computation(scratchpad_t(1, 2, 3)); will be destroyed as soon as initialize_computation is done, right? Storing the reference inside the xyz object for later user would be an extremely bad idea.

self() doesn't need to be a member method, it can be a templated function

Yes, that is also possible, although I would rename it to make the intention clearer:

template <typename T>
T& as_lvalue(T&& x)
{
    return x;
}
于 2010-09-16T22:30:12.113 に答える
4

問題はこれだけですか:

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);

醜いですか?もしそうなら、これに変更してみませんか?:

auto useless_temp = factory(rng_parm);
于 2010-09-16T21:58:48.217 に答える
3

個人的には、const_castよりも見たいですmutable。を見たときmutable、私は誰かが論理的なことconstをしていると思い込んでいて、それについてあまり考えていません。const_castただし、このようなコードはそうあるべきであるため、危険信号が発生します。

1つのオプションは、shared_ptrauto_ptr何をしているのかにもよりますがfactory)のようなものを使用して値で渡すことです。これにより、コピーコストが回避され、単一のインスタンスのみが維持されますが、ファクトリメソッドから渡すことができます。

于 2010-09-16T22:15:12.623 に答える
0

オブジェクトをヒープに割り当てると、コードを次のように変換できる場合があります。

std::auto_ptr<scratch_t> create_scratch();

foo( *create_scratch() );

ファクトリはauto_ptr、スタック内の代わりにオブジェクトを作成して返します。返されたauto_ptrテンポラリはオブジェクトの所有権を取得しますが、テンポラリで非 const メソッドを呼び出すことが許可されており、ポインターを逆参照して実際の参照を取得できます。次のシーケンス ポイントでスマート ポインターが破棄され、メモリが解放されます。scratch_t同じものを連続して異なる関数に渡す必要がある場合は、スマート ポインターをキャプチャするだけです。

std::auto_ptr<scratch_t> s( create_scratch() );
foo( *s );
bar( *s );

std::unique_ptrこれは、今後の標準で置き換えることができます。

于 2010-09-17T07:50:54.397 に答える
0

メソッドを使用して単純に非 const 参照を返すという彼の提案に対する回答として、FredOverflow の応答をマークしました。これは C++03 で機能します。そのソリューションでは、スクラッチパッドのような型ごとにメンバー メソッドが必要ですが、C++0x では、そのメソッドを任意の型に対してより一般的に記述することもできます。

template <typename T> T & temp(T && temporary_value) {return temporary_value;}

この関数は、通常の左辺値参照を単純に転送し、右辺値参照を左辺値参照に変換します。もちろん、これを行うと、結果が無視される変更可能な値が返されます。これはたまたま私が望んでいるものですが、一部のコンテキストでは奇妙に思えるかもしれません。

于 2010-09-17T07:43:34.850 に答える