Quelle est la différence entre l'ancien alloctaor :: construct et le nouveau constructeur explicite?

15

Comme je sais, std::allocator<T>::constructne prend que deux paramètres sur l'ancienne version de C ++; le premier est un pointeur vers une mémoire brute non construite dans laquelle nous voulons construire un objet de type Tet le second est une valeur de type d'élément pour initialiser cet objet. Ainsi, le constructeur de copie est invoqué:

struct Foo {
    Foo(int, int) { cout << "Foo(int, int)" << endl; }
    /*explicit*/ Foo(int) { cout << "Foo(int)" << endl; }
    Foo(const Foo&) { cout << "Foo(const Foo&)" << endl; }
};

int main(int argc, char* argv[]) {


    allocator<Foo> a;
    Foo* const p = a.allocate(200, NULL); // second parameter is required on C++98 but on C++11 it is optional
//  Foo* const p = a.allocate(200); // works fine on C++11 but not on C++98

    a.construct(p, 5, 7); // works on C++ 11 and up but not C++98
    a.construct(p, 10);// works on both
    a.destroy(p);
    a.destroy(p + 1);
    a.deallocate(p, 200);



    std::cout << std::endl;
}
  • Pourquoi en C ++ 98 a.construct(p, 10)appeler le constructeur de copie mais en C ++ 11 et supérieur appelle juste le constructeur qui prend un entier?

  • Est -ce que cela signifie sur C ++ 11 en raison d'une optimisation copie-élision , même si le constructeur Foo(int)est des explicittravaux sur cet appel: a.construct(p, 5)travaux sur C ++ 11 même le constructeur est explicitce que je suis sûr est qu'il ne fonctionne pas sur C ++ 98 si Foo(int)est explicit.

  • Si oui, alors si je compile cette déclaration avec une sorte d' copy-elisionoptimisation désactivante , le compilateur échouera? Je vous remercie.

Itachi Uchiwa
la source
3
Réponse courte: jusqu'à C ++ 11, il n'y avait pas de transmission parfaite . Détails fournis ci-dessous par @flyx. Notez qu'aucune élision de copie n'est impliquée (pas de valeur de passage ou de retour par valeur).
Daniel Langr

Réponses:

13

En effet, la déclaration de construct changé en C ++ 11 :

void construct( pointer p, const_reference val );  (1)  (until C++11)
template< class U, class... Args >
void construct( U* p, Args&&... args );            (2)  (since C++11)

La première déclaration appelle le constructeur de copie, tandis que la deuxième déclaration appelle un constructeur qui correspond à la liste d'arguments donnée. Cela pourrait être le constructeur de copie, mais aussi un autre constructeur comme vous l'avez vu dans votre code.

a.construct(p, 10)appelle le constructeur de copie en C ++ 98 car le 10est implicitement converti en Foovia le Foo(int)constructeur. Cette conversion n'est pas nécessaire en C ++ 11 car il existe un constructeur correspondant qui prend un int(exactement le constructeur qui a été utilisé pour la conversion en C ++ 98). C'est également la raison pour laquelle le code ne fonctionne pas en C ++ 98 lorsque vous ajoutez explicit- il ne peut pas convertir le 10en a Foothen.

flyx
la source