Apa perbedaan antara pengalokasian lama :: konstruk dan yang baru dan konstruktor eksplisit?

15

Seperti yang saya tahu std::allocator<T>::constructhanya membutuhkan dua parameter pada versi C ++ yang lebih lama; yang pertama adalah pointer ke memori mentah, yang tidak dibangun di mana kita ingin membangun objek bertipe Tdan yang kedua adalah nilai tipe elemen untuk menginisialisasi objek tersebut. Jadi copy-constructor dipanggil:

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;
}
  • Mengapa pada C ++ 98 a.construct(p, 10)memanggil copy constructor tetapi pada C ++ 11 dan di atas hanya memanggil constructor yang mengambil integer?

  • Apakah ini berarti pada C ++ 11 karena beberapa optimasi Copy-penghilangan bunyi dlm percakapan bahkan jika konstruktor Foo(int)adalah explicitkarya panggilan seperti: a.construct(p, 5)bekerja pada C ++ 11 bahkan konstruktor adalah explicitapa yang saya yakin itu tidak bekerja pada C ++ 98 jika Foo(int)adalah explicit.

  • Jika demikian maka jika saya mengkompilasi pernyataan itu dengan semacam copy-elisionoptimasi menonaktifkan akan menyebabkan kompiler gagal? Terima kasih.

Itachi Uchiwa
sumber
3
Jawaban singkat: sampai C ++ 11, tidak ada fowarding sempurna . Detail disediakan di bawah ini oleh @flyx. Perhatikan bahwa tidak ada salinan elisi yang terlibat (tidak ada nilai demi nilai atau nilai demi nilai).
Daniel Langr

Jawaban:

13

Ini karena deklarasi construct perubahan dalam 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)

Deklarasi pertama memanggil copy constructor, sedangkan deklarasi kedua memanggil constructor yang cocok dengan daftar argumen yang diberikan. Ini bisa menjadi konstruktor salin, tetapi juga konstruktor lain seperti yang Anda lihat dalam kode Anda.

a.construct(p, 10)memanggil copy constructor di C ++ 98 karena 10secara implisit dikonversi ke Foomelalui Foo(int)constructor. Konversi ini tidak diperlukan di C ++ 11 karena ada konstruktor yang cocok yang mengambil int(persis konstruktor yang digunakan untuk mengkonversi di C ++ 98). Ini juga alasan mengapa kode tidak berfungsi di C ++ 98 ketika Anda menambahkan explicit- tidak dapat mengonversikannya 10menjadi Fooitu.

lalat
sumber