web-dev-qa-db-ja.com

なぜstd :: get_temporary_bufferが必要なのですか?

どんな目的に使うべきか 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があるのはなぜですか?


アルゴリズムを実装するための1つの使用例が Dr。Dobb's Journal、July 01、1996 で提案されました。

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

84

Stroustrupは"C++プログラミング言語"§19.4.4、SE)と述べています:

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

彼はまた、次の2つの機能の紹介を開始します。

アルゴリズムが許容範囲内で実行するには、多くの場合一時スペースが必要です。

...しかしtemporaryまたはlonger-termの定義をどこにも提供していないようです。

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

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

43
Georg Fritzsche

Microsoftの標準ライブラリの人は次のように言っています( ここ ):

  • 「get_temporary_buffer」をいつ使用するか説明してもらえますか

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

これは、sttable_partition()のようなアルゴリズムでSTLによって内部的に使用されます。これは、N3126 25.3.13 [alg.partitions]/11のような魔法の言葉がある場合に発生します。stable_partition()の複雑さは「最大(最後-最初)* log(最後-最初)スワップですが、存在する場合は、スワップの線形数のみ十分な追加メモリがあります。」 「十分なメモリがある場合」という魔法の言葉が現れると、STLはget_temporary_buffer()を使用して作業領域を獲得しようとします。可能であれば、アルゴリズムをより効率的に実装できます。それができない場合は、システムがメモリ不足に近く危険なほど実行されている(または関連する範囲が非常に大きい)ため、アルゴリズムはより遅い手法にフォールバックする可能性があります。

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

17
Jeremy

標準では、ストレージを最大n要素に割り当てると記載されています。言い換えれば、あなたの例は5つのオブジェクトだけに十分な大きさのバッファを返すかもしれません。

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

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

9
jalf

どのような目的でstd::get_temporary_buffer?

関数 はC++ 17では推奨されないため、正しい答えは「目的がないため、使用しない」です。

4
Raedwald
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以上でなければなりません。

2
OwnWaterloo

おそらく(単なる推測)、それはメモリの断片化に関係しています。一時的なメモリの割り当てと割り当て解除を頻繁に続けているが、それを行うたびに、tempを割り当てた後、割り当てを解除する前に、長期の意図したメモリを割り当てた場合、ヒープが断片化する可能性があります(私はそう思います)。

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

2
Daniel Munoz