Question Pourquoi ai-je besoin de std :: get_temporary_buffer?


Pour 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 objets T adjacents.

Je pensais que le tampon serait alloué sur la pile, 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 les objets non plus. Ai-je raison de dire que les affirmations suivantes sont équivalentes?

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

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


Un cas d'utilisation a été suggéré dans le Dr. Dobb's Journal, 1er juillet 1996 pour implémenter des algorithmes:

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


80
2017-07-16 11:25


origine


Réponses:


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

L’idée est qu’un système peut conserver un certain nombre de tampons de taille fixe prêts pour une allocation rapide n les objets peuvent donner de l'espace pour plus de n. Il peut aussi donner moins, donc une façon d'utiliser get_temporary_buffer() est de demander avec optimisme beaucoup et ensuite utiliser ce qui se passe être disponible.
  [...] Car get_temporary_buffer() est de bas niveau et susceptible d’être optimisé pour la gestion des tampons temporaires, il ne doit pas être utilisé Nouveau ou allocateur :: allocate () pour obtenir un stockage à 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 de définition de temporaire ou plus long terme nulle part.

Un anecdote dans "Des mathématiques à la programmation générique" mentionne que Stepanov a fourni une implémentation fausse de placeholder dans le design STL original, cependant:

À 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 [...]


41
2017-07-16 12:06



Le type de bibliothèque standard de Microsoft dit ce qui suit (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   exceptions, comme new (nothrow), mais il ne construit pas non plus d'objets,   contrairement à nouveau (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) * enregistrer (dernier) swaps, mais seulement un nombre linéaire de swaps s'il y a suffisamment de mémoire supplémentaire. "Quand les mots magiques" s'il y a   suffisamment de mémoire supplémentaire "apparaît, la STL utilise get_temporary_buffer () pour   essayer d'acquérir un espace de travail. Si c'est possible, alors il peut mettre en œuvre le   algorithme plus efficacement. Si ce n'est pas le cas, le système fonctionne   dangereusement proche de la mémoire (ou 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 ().


15
2017-11-11 09:07



La norme stipule qu’elle alloue le stockage pour Jusqu'à  n éléments. En d'autres termes, votre exemple peut renvoyer un tampon suffisamment grand pour 5 objets uniquement.

Il semble assez difficile d'imaginer un bon cas d'utilisation pour cela. Peut-être que si vous travaillez sur une plate-forme avec beaucoup de mémoire, 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 éviterez autant que possible l'allocation de mémoire et utiliserez un pool de mémoire ou quelque chose sur lequel vous avez un contrôle total.


9
2017-07-16 11:37



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

répondre peut être inférieur à demande.

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

la taille réelle de base doit être supérieur ou égal à exiger.


2
2017-07-16 11:41



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. La mémoire ne se fragmente donc pas.


2
2018-01-06 03:04



Pour quel but je devrais utiliser std::get_temporary_buffer?

La fonction est déconseillée en C ++ 17, la réponse correcte est maintenant "sans objet, ne l’utilisez pas".


1
2017-12-06 23:11