Was ist der Unterschied zwischen dem älteren alloctaor :: -Konstrukt und dem neuen und expliziten Konstruktor?

15

Wie ich weiß, std::allocator<T>::constructwerden in älteren Versionen von C ++ nur zwei Parameter verwendet. Der erste ist ein Zeiger auf einen unkonstruierten Rohspeicher, in dem ein Objekt vom Typ erstellt werden soll, Tund der zweite ist ein Wert vom Elementtyp, um dieses Objekt zu initialisieren. Also wird der Kopierkonstruktor aufgerufen:

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;
}
  • Warum a.construct(p, 10)ruft unter C ++ 98 der Kopierkonstruktor auf, unter C ++ 11 und höher jedoch nur der Konstruktor, der eine Ganzzahl akzeptiert?

  • Bedeutet dies , dass auf C ++ 11 wegen einer Copy-elision Optimierung auch wenn der Konstruktor Foo(int)sind explicitWerke auf diesem Aufruf: a.construct(p, 5)Arbeiten auf C ++ 11 auch der Konstruktor ist , explicitwas ich bin sicher, es ist nicht auf C nicht funktioniert ++ 98 , wenn Foo(int)ist explicit.

  • Wenn ja, wenn ich diese Anweisung mit einer Art Deaktivierungsoptimierung kompiliere, copy-elisionführt dies dazu, dass der Compiler fehlschlägt? Vielen Dank.

Itachi Uchiwa
quelle
3
Kurze Antwort: Bis C ++ 11 gab es keine perfekte Weiterleitung . Details zur Verfügung gestellt von @flyx. Beachten Sie, dass keine Kopierelision erforderlich ist (keine Übergabe nach Wert oder Rückgabe nach Wert).
Daniel Langr

Antworten:

13

Dies liegt daran, dass die Deklaration von construct in C ++ 11 geändert wurde :

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)

Die erste Deklaration ruft den Kopierkonstruktor auf, während die zweite Deklaration einen Konstruktor aufruft, der der angegebenen Liste von Argumenten entspricht. Dies kann der Kopierkonstruktor sein, aber auch ein anderer Konstruktor, wie Sie in Ihrem Code gesehen haben.

a.construct(p, 10)Ruft den Kopierkonstruktor in C ++ 98 auf, da der 10implizit Fooüber den Foo(int)Konstruktor konvertiert wird . Diese Konvertierung ist in C ++ 11 nicht erforderlich, da es einen passenden Konstruktor gibt, der ein verwendet int(genau den Konstruktor, der für die Konvertierung in C ++ 98 verwendet wurde). Dies ist auch der Grund, warum der Code beim Hinzufügen in C ++ 98 nicht funktioniert explicit- er kann den Code nicht in 10einen FooDann konvertieren .

flyx
quelle