Jaka jest różnica między starszym managerem :: construct i nowym i jawnym konstruktorem?

15

Jak wiem std::allocator<T>::constructbierze tylko dwa parametry w starszej wersji C ++; pierwszy to wskaźnik do surowej, nieskonstruowanej pamięci, w której chcemy zbudować obiekt typu, Ta drugi to wartość typu elementu w celu zainicjowania tego obiektu. Tak więc wywoływany jest konstruktor kopii:

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;
}
  • Dlaczego w C ++ 98 a.construct(p, 10)wywoływanie konstruktora kopiowania, a w C ++ 11 i nowszych wywołuje tylko konstruktor, który przyjmuje liczbę całkowitą?

  • Czy to znaczy, na C ++ 11 z powodu jakiejś optymalizacji kopiowaniem elizja nawet jeśli konstruktor Foo(int)jest explicitdziała na takiej rozmowy: a.construct(p, 5)prace nad C ++ 11 nawet konstruktor jest explicitkim jestem pewien czy to nie działa w C ++ 98, jeśli Foo(int)jest explicit.

  • Jeśli tak, to jeśli skompiluję tę instrukcję z pewnym wyłączeniem copy-elisionoptymalizacji spowoduje kompilator się nie powiedzie? Dziękuję Ci.

Itachi Uchiwa
źródło
3
Krótka odpowiedź: do C ++ 11 nie było idealnego rozwiązania . Szczegóły podane poniżej przez @flyx. Zauważ, że nie ma miejsca na wymuszenie kopiowania (brak wartości według wartości lub zwrotu według wartości).
Daniel Langr

Odpowiedzi:

13

Wynika to z faktu, że deklaracja construct zmiany w 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)

Pierwsza deklaracja wywołuje konstruktor kopiowania, a druga deklaruje konstruktor pasujący do podanej listy argumentów. Może to być konstruktor kopii, ale także inny konstruktor, jak widzieliście w kodzie.

a.construct(p, 10)wywołuje konstruktor kopiowania w C ++ 98, ponieważ 10jest on domyślnie konwertowany Foona Foo(int)konstruktor. Ta konwersja nie jest konieczna w C ++ 11, ponieważ istnieje zgodny konstruktor, który pobiera int(dokładnie konstruktor użyty do konwersji w C ++ 98). Jest to również powód, dla którego kod nie działa w C ++ 98 po dodaniu explicit- nie może przekonwertować 10go na Foowtedy.

flyx
źródło