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


84

どのような目的で使用する必要があります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つのユースケースが提案されました。

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


2
参考までstd::get_temporary_bufferに、C ++ 17では非推奨になります。
2016

1
@Deqingはい。また、C ++ 20でも、正当な理由で(以下で説明するように)削除されます。だから、見る人に沿って移動...
ニコス

回答:


44

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

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

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

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

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

「数学から一般的なプログラミングへ」逸話では、Stepanovが元のSTLデザインに偽のプレースホルダー実装を提供したと述べています。

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


12
これのVC ++の実装はoperator new、割り当てが成功するまで、連続して小さい引数で呼び出すループであるように見えます。特別な最適化はありません。
jalf 2010

9
g ++ 4.5と同じ-それはよく意図されていたようですが、ベンダーによって無視されました。
Georg Fritzsche 2010

4
この機能をcrazy_allocator
0xbadf00d 2014年

しかし、真剣に取り組みましょう。たぶん、多くのストレージを割り当てて喜んでいるでしょう。今できることは、を使用して、その膨大な量のストレージを取得するようにシステムに要求することですget_temporary_buffer。ただし、受け取った量が要求された量より少ない場合(本当に残念なことです)、私たちは持っているストレージで作業を続けようとします。bad_alloc使用可能なメモリよりも多くのメモリを割り当てようとすることによって引き起こされる例外をキャッチするよりも優れている可能性があります。ただし、実際の有用性は、適切な実装によって決まります。
0xbadf00d 2014年

@jalf C ++ 17では非推奨です:)(cppreference.comによる)。
4LegsDrivenCat 2016

17

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

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

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

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

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


9

標準では、最大 n要素にストレージを割り当てるとされています。つまり、この例では、5つのオブジェクトのみに十分な大きさのバッファーが返される場合があります。

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

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


4

どのような目的で使用する必要がありますか std::get_temporary_buffer?

この関数はC ++ 17で非推奨になったため、正解は「目的がないので使用しないでください」になりました。


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 ) );

ベースの実際のサイズは、require以上である必要があります。


2

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

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


1
非常に興味深い考え。現在、ほとんどの実装で機能するように実装されているように見えますが、これは、他のメモリ管理ルーチンとより緊密に連携して統合できる可能性があります。私は実際にこれがそれに適していることを期待して私たちに投票します、そしてBjarnesのコメントもそれを示唆しているようです。
gustaf r 2013

私は今、Bjarneがそれについて言っていることを探しました、そして彼はそれが初期化なしで速い割り当てのために設計されていると言います。したがって、アロケータのみ(初期化子ではない)のvoid *演算子new(size_t size)のようになりますが、事前に割り当てられているため、割り当てが高速です。
ダニエルムニョス2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.