web-dev-qa-db-fra.com

C ++, est-il possible d'appeler directement un constructeur, sans nouveau?

Puis-je appeler explicitement le constructeur, sans utiliser new, si j'ai déjà une mémoire pour l'objet?

class Object1{
    char *str;
public:
    Object1(char*str1){
        str=strdup(str1);
        puts("ctor");
        puts(str);
    }
    ~Object1(){
        puts("dtor");
        puts(str);
        free(str);
    }
};

Object1 ooo[2] = {
     Object1("I'm the first object"), Object1("I'm the 2nd")
};

do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory
51
osgx

Sorte de. Vous pouvez utiliser placement new pour exécuter le constructeur en utilisant la mémoire déjà allouée:

 #include <new>

 Object1 ooo[2] = {Object1("I'm the first object"), Object1("I'm the 2nd")};
 do_smth_useful(ooo);
 ooo[0].~Object1(); // call destructor

 new (&ooo[0]) Object1("I'm the 3rd object in place of first");

Donc, vous utilisez toujours le mot clé new, mais aucune allocation de mémoire n'a lieu.

76
unwind

Je pense que vous recherchez un placement nouveau. C++ FAQ Lite a un bon résumé de la façon dont vous faites cela. Il y a quelques accrochages importants à partir de cette entrée:

  1. Vous êtes censé #include <new> pour utiliser la nouvelle syntaxe de placement.
  2. Votre mémoire tampon doit être correctement alignée pour l'objet que vous créez.
  3. C'est votre travail d'appeler manuellement le destructeur.
15
Michael Kristofik

Permettez-moi de vous montrer un code sur la façon dont cela peut être fait, à la fois dans la construction et la destruction

#include <new>

// Let's create some memory where we will construct the object.
MyObject* obj = (MyObject*)malloc(sizeof(MyObject));

// Let's construct the object using the placement new
new(obj) MyObject();

// Let's destruct it now
obj->~MyObject();

// Let's release the memory we used before
free(obj);
obj = 0;

J'espère que le résumé ci-dessus clarifie les choses.

15
Cthutu

Littéralement, NON, vous ne pouvez pas le faire sans le "nouveau" mot clé. Voir toutes les réponses sur le placement nouveau pour savoir comment utiliser le mot-clé "nouveau" pour appeler le constructeur sans allouer réellement de mémoire.

5
Ben Voigt

Oui, lorsque vous avez votre propre tampon alloué, vous utilisez new placement. Brian Bondy a une bonne réponse ici dans une question connexe:

Quelles sont les utilisations du "placement nouveau"?

2
itsmatt

Vous pouvez appeler un destructeur, mais la mémoire ne sera pas récupérée et votre appel sera équivalent à un appel de fonction. Vous devez vous rappeler que sous le destructeur fait 2 choses: détruit l'objet en fonction de vos spécifications et récupère la mémoire. Puisque votre dtor sera de toute façon appelé pour un objet alloué sur la pile, l'appeler deux fois peut entraîner un comportement indéfini.

1
vehomzzz

Oui, en utilisant placement new - comme ci-dessus, mais vous pourriez envisager d'avoir une deuxième classe d'usine pour gérer le stockage, même si cela signifie copier un objet. memcpy () est généralement bon marché pour les petits objets.

1
Martin Beckett

Vous pouvez utiliser le modèle suivant

template <typename T, typename... Args>
inline void InitClass(T &t, Args... args)
{
    t.~T();
    new (&t) T(args...);
}

usage:

struct A
{
   A() {}
   A(int i) : a(i) {}
   int a;
} my_value;

InitClass(my_value);
InitClass(my_value, 5);
0
user11258054