Qual é a diferença entre o alocador mais antigo :: construct e o novo construtor explícito?

15

Como eu sei std::allocator<T>::constructleva apenas dois parâmetros na versão mais antiga do C ++; o primeiro é um ponteiro para a memória bruta, não construída, na qual queremos construir um objeto do tipo Te o segundo é um valor do tipo de elemento para inicializar esse objeto. Portanto, o copy-constructor é chamado:

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;
}
  • Por que no C ++ 98 a.construct(p, 10) chamando o construtor de cópias, mas no C ++ 11 e acima está chamando apenas o construtor que usa um número inteiro?

  • Será que isso significa em C ++ 11 por causa de alguma otimização Copy-elisão mesmo que o construtor Foo(int)é explicittrabalhos sobre tal chamada: a.construct(p, 5)funciona em C ++ 11, mesmo o construtor é explicito que eu tenho certeza é que ele não funciona em C ++ 98 se Foo(int)é explicit.

  • Em caso afirmativo, se eu compilar essa instrução com algum tipo de copy-elisionotimização desabilitante fará com que o compilador falhe? Obrigado.

Itachi Uchiwa
fonte
3
Resposta curta: até C ++ 11, não havia um encaminhamento perfeito . Detalhes fornecidos abaixo por @flyx. Observe que não há elisão de cópia envolvida (nenhuma passagem por valor ou retorno por valor).
precisa saber é o seguinte

Respostas:

13

Isso ocorre porque a declaração foi construct alterada no 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 primeira declaração chama o construtor de cópia, enquanto a segunda declaração chama um construtor que corresponde à lista de argumentos fornecida. Este poderia ser o construtor de cópia, mas também outro construtor, como você viu no seu código.

a.construct(p, 10)chama o construtor de cópia no C ++ 98 porque o 10é implicitamente convertido em Foopelo Foo(int)construtor. Essa conversão não é necessária no C ++ 11, pois existe um construtor correspondente que usa um int(exatamente o construtor usado para converter no C ++ 98). Essa também é a razão pela qual o código não funciona no C ++ 98 quando você adiciona explicit- ele não pode converter o arquivo 10em um Fooentão.

flyx
fonte