Pourquoi dois-je std :: get_temporary_buffer?

Dans quel but je devrais utiliser std::get_temporary_buffer ? Standard dit ce qui suit:

Obtient un pointeur sur le stockage suffisant pour stocker jusqu’à n objects T adjacents.

Je pensais que le tampon serait alloué sur la stack, mais ce n’est pas vrai. Selon le standard C ++, ce tampon n’est en fait pas temporaire. Quels sont les avantages de cette fonction sur la fonction globale ::operator new , qui ne construit pas non plus les objects. Ai-je raison de dire que les affirmations suivantes sont équivalentes?

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

Cette fonction n’existe-t-elle que pour le sucre syntaxique? Pourquoi y a-t-il temporary nom temporary en son nom?


Un cas d’utilisation a été suggéré dans le Dr. Dobb’s Journal du 1er juillet 1996 pour la mise en œuvre d’algorithmes:

Si aucun tampon ne peut être alloué ou s’il est plus petit que demandé, l’algorithme fonctionne toujours correctement, il ralentit simplement.

    Stroustrup dit dans “Le langage de programmation C ++” ( §19.4.4 , SE):

    L’idée est qu’un système peut garder un certain nombre de tampons de taille fixe prêts pour une allocation rapide, de sorte que la demande d’espace pour n objects peut donner de l’espace pour plus de n . Cela peut également donner moins, de sorte que l’utilisation de get_temporary_buffer() consiste à demander de manière optimiste beaucoup, puis à utiliser ce qui se passe.
    […] Comme get_temporary_buffer() est de bas niveau et susceptible d’être optimisé pour la gestion des tampons temporaires, il ne doit pas être utilisé comme alternative à new ou allocator :: allocate () pour obtenir un stockage à plus long terme.

    Il commence également l’introduction aux deux fonctions avec:

    Les algorithmes nécessitent souvent un espace temporaire pour fonctionner de manière acceptable.

    … mais ne semble pas fournir une définition de temporaire ou à long terme n’importe où.

    Une anecdote dans “De la mathématique à la programmation générique” mentionne que Stepanov a fourni une implémentation fictive dans le design STL original:

    À sa grande surprise, il a découvert des années plus tard que tous les principaux fournisseurs proposant des implémentations STL utilisent encore cette terrible implémentation […]

    Le type de bibliothèque standard de Microsoft dit ceci ( ici ):

    • Pourriez-vous peut-être expliquer quand utiliser ‘get_temporary_buffer’

    Il a un but très spécialisé. Notez qu’il ne jette pas d’exceptions, comme new (nothrow), mais qu’il ne construit pas non plus d’objects, contrairement à new (nothrow).

    Il est utilisé en interne par la STL dans des algorithmes tels que stable_partition (). Cela se produit quand il y a des mots magiques comme N3126 25.3.13 [alg.partitions] / 11: stable_partition () a de la complexité “Au plus (dernier – premier) * journal (dernier – premier) swaps, mais seulement nombre linéaire de swaps est assez de mémoire supplémentaire. ” Lorsque les mots magiques “s’il y a suffisamment de mémoire supplémentaire” apparaissent, la STL utilise get_temporary_buffer () pour tenter d’acquérir un espace de travail. Si c’est possible, il peut alors implémenter l’algorithme plus efficacement. Si ce n’est pas le cas, parce que le système est dangereusement proche de la mémoire morte (ou que les plages concernées sont énormes), l’algorithme peut revenir à une technique plus lente.

    99,9% des utilisateurs de STL n’auront jamais besoin de connaître get_temporary_buffer ().

    La norme stipule qu’elle alloue de la mémoire pour jusqu’à n éléments. En d’autres termes, votre exemple peut renvoyer un tampon suffisamment grand pour 5 objects uniquement.

    Il semble assez difficile d’imaginer un bon cas d’utilisation pour cela. Peut-être que si vous travaillez sur une plate-forme dont la mémoire est très restreinte, c’est un moyen pratique d’obtenir «autant de mémoire que possible».

    Mais sur une plate-forme aussi limitée, j’imagine que vous évitez autant que possible l’allocation de mémoire et que vous utilisez un pool de mémoire ou quelque chose sur lequel vous avez un contrôle total.

     ptrdiff_t request = 12 pair p = get_temporary_buffer(request); int* base = p.first; ptrdiff_t respond = p.sencond; assert( is_valid( base, base + respond ) ); 

    répondre peut être inférieure à la demande .

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

    la taille réelle de la base doit être supérieure ou égale à celle requirejse .

    Peut-être (pour deviner) que cela a quelque chose à voir avec la fragmentation de la mémoire. Si vous continuez à allouer et à désallouer de la mémoire temporelle, mais à chaque fois que vous le faites, vous allouez de la mémoire à long terme après avoir alloué le temp, mais vous pouvez vous retrouver avec un tas fragmenté (je suppose).

    Ainsi, get_temporary_buffer pourrait être conçu comme un bloc de mémoire plus important que vous-auriez besoin, alloué une fois (il y a peut-être de nombreux blocs prêts à accepter plusieurs requêtes), et chaque fois que vous avez besoin de mémoire morceaux. Donc, la mémoire n’est pas fragmentée.

    Dans quel but je devrais utiliser std::get_temporary_buffer?

    La fonction est obsolète en C ++ 17, la réponse correcte est maintenant “sans intérêt, ne l’utilisez pas”.