Opérateurs new
et delete
C++ prend en charge l’allocation dynamique et la désallocation d’objets à l’aide des opérateurs et delete
des new
opérateurs. Ces opérateurs allouent de la mémoire pour les objets d’un pool appelé magasin gratuit (également appelé tas). L’opérateur new
appelle la fonction operator new
spéciale, et l’opérateur delete
appelle la fonction operator delete
spéciale.
Pour obtenir la liste des fichiers de bibliothèque dans la bibliothèque runtime C et la bibliothèque C++ Standard, consultez fonctionnalités de la bibliothèque CRT.
Opérateur new
Le compilateur traduit une instruction telle que celle-ci en un appel à la fonction operator new
:
char *pch = new char[BUFFER_SIZE];
Si la requête concerne zéro octets de stockage, operator new
retourne un pointeur vers un objet distinct. Autrement dit, des appels répétés pour operator new
retourner différents pointeurs.
En cas d’insuffisance de mémoire pour la demande d’allocation, operator new
lève une std::bad_alloc
exception. Sinon, elle retourne nullptr
si vous avez utilisé le formulaire new(std::nothrow)
de placement ou si vous avez lié dans la prise en charge non levéeoperator new
. Pour plus d’informations, consultez Comportement d’échec d’allocation.
Les deux étendues des operator new
fonctions sont décrites dans le tableau suivant.
Étendue des operator new
fonctions
Opérateur | Portée |
---|---|
::operator new |
Global |
nom de classe::operator new |
Classe |
Le premier argument de operator new
doit être de type size_t
et le type de retour est toujours void*
.
La fonction globale operator new
est appelée lorsque l’opérateur est utilisé pour allouer des objets de types intégrés, des objets de type de classe qui ne contiennent pas de fonctions définies par operator new
l’utilisateur new
et des tableaux de n’importe quel type. Lorsque l’opérateur new
est utilisé pour allouer des objets d’un operator new
type de classe où un operator new
est défini, cette classe est appelée.
Une operator new
fonction définie pour une classe est une fonction membre statique (qui ne peut pas être virtuelle) qui masque la fonction globale operator new
pour les objets de ce type de classe. Considérez le cas où new
est utilisé pour allouer et définir la mémoire sur une valeur donnée :
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
Argument fourni entre parenthèses à new
passer en Blanks::operator new
tant qu’argument chInit
. Toutefois, la fonction globale operator new
est masquée, ce qui provoque le code suivant pour générer une erreur :
Blanks *SomeBlanks = new Blanks;
Le compilateur prend en charge le tableau new
de membres et delete
les opérateurs dans une déclaration de classe. Par exemple :
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Comportement d’échec d’allocation
La new
fonction de la bibliothèque standard C++ prend en charge le comportement spécifié dans la norme C++ depuis C++98. En cas d’insuffisance de mémoire pour une demande d’allocation, operator new
lève une std::bad_alloc
exception.
Un ancien code C++ a retourné un pointeur Null pour une allocation ayant échoué. Si vous avez du code qui attend la version non levée de new
, liez votre programme avec nothrownew.obj
. Le nothrownew.obj
fichier remplace global operator new
par une version qui retourne nullptr
si une allocation échoue. operator new
ne lève std::bad_alloc
plus . Pour plus d’informations sur nothrownew.obj
les autres fichiers d’options de l’éditeur de liens, consultez les options de lien.
Vous ne pouvez pas combiner de code qui case activée pour les exceptions de global operator new
avec du code qui case activée s pour les pointeurs Null dans la même application. Toutefois, vous pouvez toujours créer un local operator new
de classe qui se comporte différemment. Cette possibilité signifie que le compilateur doit agir de manière défensive par défaut et inclure des case activée pour les retours de pointeur Null dans new
les appels. Pour plus d’informations sur un moyen d’optimiser ces case activée de compilateur, consultez /Zc:throwingnew
.
Gestion d'une mémoire insuffisante
La façon dont vous testez une allocation ayant échoué à partir d’une new
expression dépend de l’utilisation du mécanisme d’exception standard ou d’un nullptr
retour. C++ standard s’attend à ce qu’un allocateur lève std::bad_alloc
soit une classe dérivée de std::bad_alloc
. Vous pouvez gérer une telle exception, comme illustré dans cet exemple :
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
Lorsque vous utilisez la nothrow
forme de new
, vous pouvez tester un échec d’allocation, comme indiqué dans cet exemple :
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Vous pouvez tester une allocation de mémoire ayant échoué lorsque vous avez utilisé nothrownew.obj
un fichier pour remplacer global operator new
, comme indiqué ici :
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Vous pouvez fournir un gestionnaire pour les demandes d’allocation de mémoire ayant échoué. Il est possible d’écrire une routine de récupération personnalisée pour gérer une telle défaillance. Il peut, par exemple, libérer une mémoire réservée, puis autoriser l’allocation à s’exécuter à nouveau. Pour plus d’informations, consultez _set_new_handler
.
Opérateur delete
La mémoire allouée dynamiquement à l’aide de l’opérateur new
peut être libérée à l’aide de l’opérateur delete
. L’opérateur delete appelle la operator delete
fonction, qui libère de la mémoire au pool disponible. L’utilisation de l’opérateur delete
entraîne également l’appel du destructeur de classe (le cas échéant).
Il existe des fonctions globales et délimitées par des operator delete
classes. operator delete
Une seule fonction peut être définie pour une classe donnée ; si elle est définie, elle masque la fonction globaleoperator delete
. La fonction globale operator delete
est toujours appelée pour les tableaux de n’importe quel type.
Fonction globale operator delete
. Deux formulaires existent pour les fonctions globales operator delete
et membres operator delete
de classe :
void operator delete( void * );
void operator delete( void *, size_t );
Un seul des deux formulaires précédents peut être présent pour une classe donnée. Le premier formulaire prend un seul argument de type void *
, qui contient un pointeur vers l’objet à libérer. Le deuxième formulaire, dimensionné la désallocation, prend deux arguments : le premier est un pointeur vers le bloc de mémoire à libérer, et le deuxième est le nombre d’octets à libérer. Le type de retour des deux formulaires est void
(operator delete
ne peut pas retourner une valeur).
L’intention du deuxième formulaire est d’accélérer la recherche de la catégorie de taille correcte de l’objet à supprimer. Ces informations ne sont souvent pas stockées près de l’allocation elle-même et sont probablement non mises en cache. Le deuxième formulaire est utile lorsqu’une operator delete
fonction d’une classe de base est utilisée pour supprimer un objet d’une classe dérivée.
La operator delete
fonction est statique, de sorte qu’elle ne peut pas être virtuelle. La operator delete
fonction obéit au contrôle d’accès, comme décrit dans Le contrôle d’accès aux membres.
L’exemple suivant montre les fonctions définies par operator new
operator delete
l’utilisateur conçues pour journaliser les allocations et les désallocations de mémoire :
#include <iostream>
using namespace std;
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock ) {
static int fInOpNew = 0; // Guard flag.
if ( fLogMemory && !fInOpNew ) {
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem ) {
static int fInOpDelete = 0; // Guard flag.
if ( fLogMemory && !fInOpDelete ) {
fInOpDelete = 1;
clog << "Memory block " << cBlocksAllocated--
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] ) {
fLogMemory = 1; // Turn logging on
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i ) {
char *pMem = new char[10];
delete[] pMem;
}
fLogMemory = 0; // Turn logging off.
return cBlocksAllocated;
}
Le code précédent peut être utilisé pour détecter les « fuites de mémoire », c’est-à-dire la mémoire allouée sur le magasin gratuit, mais jamais libérée. Pour détecter les fuites, les opérateurs globaux et delete
globaux new
sont redéfinis pour compter l’allocation et la désallocation de la mémoire.
Le compilateur prend en charge le tableau new
de membres et delete
les opérateurs dans une déclaration de classe. Par exemple :
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour