В чем разница между старым alloctaor :: construct и новым и явным конструктором?

15

Как я знаю, std::allocator<T>::constructпринимает только два параметра в более старой версии C ++; первый - указатель на необработанную неструктурированную память, в которой мы хотим создать объект типа, Tа второй - значение типа элемента для инициализации этого объекта. Итак, конструктор копирования вызывается:

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;
}
  • Почему в C ++ 98 a.construct(p, 10)вызов конструктора копирования, а в C ++ 11 и выше вызывает только тот конструктор, который принимает целое число?

  • Означают ли это на C ++ 11 из - за некоторую оптимизацию копирования Elision даже если конструктор Foo(int)является explicitработой по такому вызову: a.construct(p, 5)работает на C ++ 11 даже конструктор , explicitчто я уверен , это не работает на C ++ 98 , если Foo(int)есть explicit.

  • Если так, то если я скомпилирую это утверждение с каким-то отключением copy-elisionоптимизации, это приведет к сбою компилятора? Спасибо.

Итачи Учива
источник
3
Краткий ответ: до C ++ 11 не было идеальной работы . Подробности предоставлены ниже @flyx. Обратите внимание, что в этом случае не используется допуск копирования (передача по значению или возврат по значению).
Даниэль Лангр

Ответы:

13

Это потому, что объявление об construct изменении в 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)

Первое объявление вызывает конструктор копирования, а второе - конструктор, который соответствует заданному списку аргументов. Это может быть как конструктор копирования, так и другой конструктор, как вы видели в своем коде.

a.construct(p, 10)вызывает конструктор копирования в C ++ 98, потому что 10он неявно преобразуется Fooв Foo(int)конструктор. Это преобразование не является необходимым в C ++ 11, поскольку существует соответствующий конструктор, который принимает int(именно тот конструктор, который использовался для преобразования в C ++ 98). Это также причина , почему код не работает в C ++ 98 при добавлении explicit- он не может преобразовать 10к Fooтогда.

flyx
источник