137 votes

Appeler des constructeurs en c ++ sans nouveau

J'ai souvent vu des personnes créer des objets en C ++ en utilisant

 Thing myThing("asdf");
 

Au lieu de

 Thing myThing = myThing("asdf");
 

Cela semble fonctionner (avec gcc), du moins tant qu'aucun modèle n'est impliqué. Ma question maintenant, la première ligne est-elle correcte et si oui devrais-je l'utiliser?

145voto

JaredPar Points 333733

Les deux lignes sont en fait correcte, mais ne subtilement différentes choses.

La première ligne crée un nouvel objet sur la pile par l'appel d'un constructeur de format Thing(const char*).

Le second est un peu plus complexe. Essentiellement, il effectue les opérations suivantes

  1. Créer un objet de type Thing en utilisant le constructeur Thing(const char*)
  2. Créer un objet de type Thing en utilisant le constructeur Thing(const Thing&)
  3. Appelez ~Thing() sur l'objet créé à l'étape 1

30voto

knittl Points 64110

Je suppose que la deuxième ligne vous fait dire:

MyThing *myThing = new MyThing("uiae");

ce qui serait le niveau moyen de créer de nouvelles dynamiques des objets (nécessaire pour la liaison dynamique et le polymorphisme et le stockage de leur adresse à un pointeur. votre code ne ce JaredPar décrites, à savoir la création de deux objets, affecter operator= et la suppression de l'un d'eux.

En revanche, ceci:

MyThing myThing("uiae");

crée un objet statique qui est détruit automatiquement à la sortie de l'étendue actuelle.

21voto

Douglas Leeder Points 29986

Le compilateur peut bien optimiser la deuxième forme dans la première, mais ce n’est pas obligatoire.

 #include <iostream>

class A
{
    public:
        A() { std::cerr << "Empty constructor" << std::endl; }
        A(const A&) { std::cerr << "Copy constructor" << std::endl; }
        A(const char* str) { std::cerr << "char constructor: " << str << std::endl; }
        ~A() { std::cerr << "destructor" << std::endl; }
};

void direct()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a(__FUNCTION__);
    static_cast<void>(a);
}

void assignment()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a = A(__FUNCTION__);
    static_cast<void>(a);
}

void prove_copy_constructor_is_called()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a(__FUNCTION__);
    A b = a;
    static_cast<void>(b);
}

int main()
{
    direct();
    assignment();
    prove_copy_constructor_is_called();
    return 0;
}
 

Sortie de gcc 4.4:

 TEST: direct
char constructor: direct
destructor

TEST: assignment
char constructor: assignment
destructor

TEST: prove_copy_constructor_is_called
char constructor: prove_copy_constructor_is_called
Copy constructor
destructor
destructor
 

10voto

Stephen Cross Points 550

Tout simplement, les deux lignes créent l'objet sur la pile, plutôt que sur le tas comme le fait "le nouveau". La deuxième ligne implique en fait un deuxième appel à un constructeur de copie, il faut donc l’éviter (il faut également le corriger comme indiqué dans les commentaires). Vous devez utiliser la pile autant que possible pour les petits objets car elle est plus rapide. Toutefois, si vos objets vont survivre plus longtemps que le cadre de la pile, c'est clairement le mauvais choix.

2voto

Puppy Points 90818

Idéalement, un compilateur optimiserait le second, mais ce n’est pas obligatoire. Le premier est le meilleur moyen. Cependant, il est très important de comprendre la distinction entre pile et tas en C ++, car vous devez gérer votre propre mémoire de tas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X