Neden std :: get_temporary_buffer'a ihtiyacım var?


84

Ne amaçla kullanmalıyım std::get_temporary_buffer? Standart şunları söylüyor:

N bitişik T nesnesine kadar depolamaya yetecek depolama için bir işaretçi elde eder.

Tamponun yığın üzerinde tahsis edileceğini düşündüm, ancak bu doğru değil. C ++ Standardına göre bu tampon aslında geçici değildir. Bu fonksiyonun ::operator new, nesneleri oluşturmayan global fonksiyona göre ne gibi avantajları vardır? Aşağıdaki ifadelerin eşdeğer olduğu konusunda haklı mıyım?

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

Bu işlev yalnızca sözdizimi şekeri için mi var? Adında neden var temporary?


Dr. Dobb's Journal, 01 Temmuz 1996'da bir kullanım örneği önerildiAlgoritmaları uygulamak için :

Hiçbir arabellek ayrılamazsa veya istenenden daha küçükse, algoritma hala doğru şekilde çalışır, yalnızca yavaşlar.


2
Bilginize, std::get_temporary_bufferC ++ 17'de kullanımdan kaldırılacaktır.
Deqing

1
@Deqing Evet. Ayrıca C ++ 20'de ve iyi bir nedenden dolayı kaldırılacaktır (aşağıda belirtilenler gibi). Öyleyse izleyiciyle birlikte hareket edin ..
Nikos

Yanıtlar:


44

Stroustrup "The C ++ Programming Language" ( §19.4.4 , SE):

Fikir sistemi hızlı ayırma hazır sabit boyutlu tamponlar, bir dizi devam edebilir, bu yüzden, için alan talep n nesneleri daha fazla yer verebilir n . Bununla birlikte, daha az verim de sağlayabilir, bu nedenle kullanmanın bir yolu get_temporary_buffer()iyimser bir şekilde çok şey istemek ve sonra mevcut olanı kullanmaktır.
[...] get_temporary_buffer()Düşük seviyeli olduğundan ve geçici arabellekleri yönetmek için optimize edilmesi muhtemel olduğundan, daha uzun süreli depolama elde etmek için yeni veya allocator :: ayırıcıya alternatif olarak kullanılmamalıdır .

Ayrıca iki işleve şu şekilde giriş yapmaya başlar:

Algoritmalar genellikle kabul edilebilir bir performans için geçici alan gerektirir.

... ancak hiçbir yerde geçici veya uzun vadeli bir tanım sağlamıyor gibi görünüyor .

"Matematikten Genel Programlamaya" daki bir anekdot , Stepanov'un orijinal STL tasarımında sahte bir yer tutucu uygulaması sağladığından bahsediyor, ancak:

Yıllar sonra, STL uygulamaları sağlayan tüm büyük satıcıların hala bu korkunç uygulamayı kullandığını keşfetti [...]


12
Görünüşe göre VC ++ 'ın bunun uygulaması operator new, ayırma başarılı olana kadar art arda daha küçük argümanlarla çağrı yapan bir döngüdür . Orada özel optimizasyon yok.
jalf

9
G ++ 4.5 ile aynı - iyi tasarlanmış ama satıcılar tarafından göz ardı edilmiş gibi görünüyor.
Georg Fritzsche

4
Bu işlevselliğicrazy_allocator
0xbadf00d

Ama ciddi kalalım - Belki çok fazla depolama alanı ayırmaktan mutlu olur. Şimdi yapabileceğimiz şey, sistemden o kadar büyük miktarda depolama elde etmesini istemek - kullanarak get_temporary_buffer. Ancak, talep edilen miktardan daha azını alırsak (ne yazık ki) elimizdeki depolama alanıyla işimizi yapmaya çalışıyoruz. bad_allocMevcut olandan daha fazla bellek ayırma girişiminin neden olduğu özel durumları yakalamaktan daha iyi olabilir . Bununla birlikte, gerçek fayda, iyi bir uygulama ile kalır ve düşer.
0xbadf00d

@jalf C ++ 17'de kullanımdan kaldırıldı :) ( cppreference.com'a göre ).
4LegsDrivenCat

17

Microsoft'un standart kitaplık görevlisi şunları söylüyor ( burada ):

  • "Get_temporary_buffer" ı ne zaman kullanacağınızı açıklayabilir misiniz?

Çok özel bir amacı var. New (nothrow) gibi istisnalar atmadığını, ancak new (nothrow) gibi nesneler de oluşturmadığını unutmayın.

Stabil_partition () gibi algoritmalarda STL tarafından dahili olarak kullanılır. Bu, N3126 25.3.13 [alg.partitions] / 11 gibi sihirli kelimeler olduğunda gerçekleşir: stabil_partition () karmaşıklığa sahiptir "En fazla (son - ilk) * log (son - ilk) takas, ancak varsa yalnızca doğrusal sayıda takas vardır yeterli ekstra hafıza. " "Yeterince fazladan bellek varsa" sihirli kelimeleri göründüğünde, STL çalışma alanını elde etmeye çalışmak için get_temporary_buffer () kullanır. Yapabilirse, algoritmayı daha verimli bir şekilde uygulayabilir. Başaramazsa, sistem tehlikeli bir şekilde bellek yetersizliğine yakın çalıştığı için (veya ilgili aralıklar çok büyükse), algoritma daha yavaş bir tekniğe geri dönebilir.

STL kullanıcılarının% 99,9'u get_temporary_buffer () hakkında bilgi sahibi olmak zorunda kalmayacak.


9

Standart, öğelere kadar depolama alanı ayırdığını söylüyor n. Başka bir deyişle, örneğiniz yalnızca 5 nesne için yeterince büyük bir tampon döndürebilir.

Yine de bunun için iyi bir kullanım durumu hayal etmek oldukça zor görünüyor. Belki de hafızayla sınırlı bir platform üzerinde çalışıyorsanız, "mümkün olduğunca fazla hafıza" elde etmenin uygun bir yoludur.

Ancak böylesine kısıtlı bir platformda, bellek ayırıcıyı olabildiğince atlayacağınızı ve bir bellek havuzunu veya üzerinde tam kontrol sahibi olduğunuz bir şeyi kullanacağınızı hayal ediyorum.


4

Ne amaçla kullanmalıyım std::get_temporary_buffer?

İşlev , C ++ 17'de kullanımdan kaldırılmıştır, bu nedenle artık doğru yanıt "amaçsız olarak kullanmayın" şeklindedir.


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

yanıt talep edilenden daha az olabilir .

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

gerçek boyutu temel zorunluluk daha büyük ya da eşit gerektirir .


2

Belki de (sadece bir tahmin) hafıza parçalanmasıyla bir ilgisi vardır. Geçici belleği ayırmaya ve serbest bırakmaya yoğun bir şekilde devam ederseniz, ancak bunu her yaptığınızda, geçici olarak ayırdıktan sonra ancak serbest bırakmadan önce uzun vadeli amaçlanan bir bellek ayırırsanız, parçalanmış bir yığın elde edebilirsiniz (sanırım).

Dolayısıyla, get_temporary_buffer, bir kez ayrılmış olan ihtiyaç duyacağınızdan daha büyük bir bellek parçası olarak tasarlanabilir (belki birden çok isteği kabul etmeye hazır birçok yığın vardır) ve belleğe her ihtiyacınız olduğunda yalnızca birini alırsınız parçalar. Böylece hafıza parçalanmaz.


1
Çok ilginç düşünce. Şu anda çoğu uygulama tarafından işe yarayan bir şeyi yapalım gibi uygulanıyor gibi görünse de , bu çok daha sıkı bir şekilde desteklenebilir ve bellek yönetim rutinlerinin geri kalanıyla entegre edilebilir. Aslında bunun uygun olmasını bekliyorum ve Bjarnes yorumları da bunu ima ediyor gibi görünüyor.
gustaf r

Şimdi Bjarne'ın bunun hakkında söylediklerini aradım ve başlatmadan hızlı tahsis için tasarlandığını söylüyor. Bu nedenle, yalnızca ayırıcı (başlatıcı olmayan) void * operatörü new (size_t size) gibi olur, ancak önceden tahsis edildiğinden ayırması daha hızlıdır.
Daniel Munoz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.