87

どのような目的で使用する必要がありますstd::get_temporary_bufferか? 標準は次のように述べています。

最大 n 個の隣接する T オブジェクトを格納するのに十分なストレージへのポインターを取得します。

バッファはスタックに割り当てられると思っていましたが、そうではありません。C++ 標準によると、このバッファは実際には一時的ではありません。::operator newオブジェクトを構築しないグローバル関数よりも、この関数にはどのような利点がありますか。次のステートメントは同等であるというのは正しいですか?

int* x;
x = std::get_temporary_buffer<int>( 10 ).first;
x = static_cast<int*>( ::operator new( 10*sizeof(int) ) );

この関数は構文シュガーに対してのみ存在しますか? なぜtemporaryその名前にあるのですか?


1996 年 7 月 1 日の Dr. Dobb's Journal で、アルゴリズムを実装するための1 つのユース ケースが提案されました。

バッファーを割り当てられない場合、または要求されたサイズよりも小さい場合でも、アルゴリズムは正しく機能しますが、速度が低下するだけです。

4

6 に答える 6

47

Stroustrup は、「C++ プログラミング言語」 ( §19.4.4、SE) で次のように述べています。

この考え方は、 n 個のオブジェクトのスペースを要求するとn個を超えるスペースが得られるように、システムが多数の固定サイズのバッファーを高速割り当ての準備ができている状態に保つことができるというものです。ただし、収穫量が少なくなる可能性もあるため、get_temporary_buffer()楽観的に多くを求めてから、たまたま利用できるものを使用することも使用方法の 1 つです。
[...]get_temporary_buffer()は低レベルであり、一時バッファーの管理用に最適化される可能性が高いため、長期間のストレージを取得するためにnewまたはallocator::allocate()の代わりとして使用しないでください。

彼はまた、次のように 2 つの関数の紹介を開始します。

アルゴリズムは、多くの場合、適切に実行するために一時的なスペースを必要とします。

...しかし、一時的または長期的な定義をどこにも提供していないようです。

"From Mathematics to Generic Programming"逸話では、Stepanov が元の STL 設計で偽のプレースホルダー実装を提供したと述べています。

驚いたことに、彼は数年後、STL 実装を提供するすべての主要ベンダーがまだこのひどい実装を使用していることを発見しました [...]

于 2010-07-16T12:06:16.963 に答える
19

Microsoft の標準ライブラリ担当者は、次のように述べています ( here ):

  • 「get_temporary_buffer」をいつ使用するか説明していただけますか

それは非常に特殊な目的を持っています。new (nothrow) のように例外をスローしませんが、new (nothrow) とは異なり、オブジェクトも構築しないことに注意してください。

これは、stable_partition() などのアルゴリズムで STL によって内部的に使用されます。これは、N3126 25.3.13 [alg.partitions]/11: stable_partition() has complex のようなマジック ワードがある場合に発生します余分なメモリは十分です。」「十分な追加メモリがある場合」という魔法の言葉が表示されると、STL は get_temporary_buffer() を使用して作業領域を取得しようとします。可能であれば、アルゴリズムをより効率的に実装できます。システムが危険なほどメモリ不足に近い状態で実行されている (または関連する範囲が非常に大きい) ためにそれができない場合、アルゴリズムはより低速な手法にフォールバックできます。

STL ユーザーの 99.9% は、get_temporary_buffer() について知る必要はありません。

于 2014-11-11T09:07:37.490 に答える
9

標準では、最大 まで nの要素にストレージを割り当てると述べています。言い換えれば、あなたの例は、5 つのオブジェクトのみに十分な大きさのバッファーを返す可能性があります。

ただし、これの適切な使用例を想像するのはかなり難しいようです。おそらく、メモリに非常に制約のあるプラットフォームで作業している場合、「できるだけ多くのメモリ」を取得するのに便利な方法です。

しかし、このような制約のあるプラットフォームでは、メモリ アロケータを可能な限りバイパスし、メモリ プールまたは完全に制御できるものを使用すると思います。

于 2010-07-16T11:37:28.087 に答える
2

おそらく(単なる推測ですが)メモリの断片化と関係があります。一時メモリの割り当てと割り当て解除を頻繁に繰り返していて、そのたびに一時メモリを割り当てた後、割り当てを解除する前に長期的なメモリを割り当てると、断片化されたヒープが発生する可能性があります (私は推測します)。

したがって、get_temporary_buffer は、必要以上に大きなメモリ チャンクを一度に割り当てることを意図している可能性があり (おそらく、複数の要求を受け入れる準備ができているチャンクが多数ある)、メモリが必要になるたびに、次のいずれかを取得するだけです。チャンク。したがって、メモリは断片化されません。

于 2012-01-06T03:04:31.310 に答える
2
ptrdiff_t            request = 12
pair<int*,ptrdiff_t> p       = get_temporary_buffer<int>(request);
int*                 base    = p.first;
ptrdiff_t            respond = p.sencond;
assert( is_valid( base, base + respond ) );

ご希望に添えない場合がございます。

size_t require = 12;
int*   base    = static_cast<int*>( ::operator new( require*sizeof(int) ) );
assert( is_valid( base, base + require ) );

baseの実際のサイズはrequire以上でなければなりません。

于 2010-07-16T11:41:08.063 に答える