por que excluir explicitamente o construtor?

93

Quando / por que eu desejaria excluir explicitamente meu construtor? Supondo que o motivo seja para impedir seu uso, por que não fazê-lo private?

class Foo
{ 
  public: 
    Foo() = delete; 
};
cinza
fonte
14
Ele meio que combina bem = default, nem mesmo a classe pode usá-lo, e eu pessoalmente prefiro ver Uso de função excluída. sobre A função é privada. O primeiro afirma explicitamente "Isso não deve ser usado." Se alguma coisa sair disso, o fato de a classe não ser capaz de usá-lo realmente faz uma diferença semântica.
chris
15
Sinceramente, acho que as pessoas estão começando a ficar agressivas com os votos apertados. Não vejo como isso não seja construtivo.
Luchian Grigore
4
@LuchianGrigore: Concordo. Tenho me perguntado por que a comunidade se tornou tão mais rígida para mim. Eu não vejo o ponto.
Ed S.
11
Como eu raramente uso C ++ 11, isso é mais informativo para mim do que o OP provavelmente percebe. Eu nem sabia que você poderia marcar um construtor para delete. Tanto a pergunta quanto a resposta de Luchian podem ser facilmente qualificadas como construtivas. Qualquer um que não respire os pontos mais delicados do C ++ 11, mas precisará em breve, obterá algo de ambos.
WhozCraig 01 de

Respostas:

87

E se:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

versus

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

São coisas basicamente diferentes. privateinforma que apenas membros da classe podem chamar aquele método ou acessar aquela variável (ou amigos, é claro). Nesse caso, é legal para um staticmétodo dessa classe (ou qualquer outro membro) chamar um privateconstrutor de uma classe. Isso não vale para construtores excluídos.

Experimente aqui .

Luchian Grigore
fonte
3
Você não precisa declarar Foo () de forma alguma, se declarar Foo (int). Foo () não será gerado e, portanto, Foo f é inválido de qualquer maneira. Portanto, seu exemplo não mostra o caso do construtor excluído. Veja você mesmo - ideone.com/mogiIF
marque em
1
@mark eu escrevi 2 construtores para provar o ponto. Vou editar para que fique claro para todos.
Luchian Grigore
1
Eu entendo a diferença, apenas não entendo o valor agregado da instrução delete em geral e para um construtor em particular. Afinal, eu poderia especificar um construtor padrão privado sem o corpo. Então, o código também falha, apenas durante a vinculação. Bem, posso ver que delete transmite a intenção de forma mais explícita, mas é só isso.
marcar
11
@mark Sim, essa seria a maneira C ++ 98 de fazer as coisas. Mas, IMHO, transmitir a intenção com clareza é na verdade uma coisa muito importante na programação em geral. Neste caso, alguns leitores podem ver um construtor privado indefinido e assumir que é acidental e apenas adicionar uma definição para ele, especialmente se a definição for tão trivial quanto um construtor padrão (Sim, ter um comentário ajuda, mas preferimos muito mais o compilador - aplicação sobre a aplicação de comentários). Por ter nossa intenção mais clara, também obtemos uma mensagem de erro muito melhor que diz "excluído explicitamente" em vez de "referência indefinida".
mpark
2
Sinceramente, não entendo como isso responde à pergunta principal. A pergunta no título e a primeira pergunta do OP no post era: Quando / por que eu iria querer excluir explicitamente meu construtor?
Alexander Bolinsky
11

por que excluir explicitamente o construtor?

Outro motivo:
eu uso deletequando quero garantir que uma classe seja chamada com um inicializador. Eu considero uma maneira muito elegante de conseguir isso sem verificações de tempo de execução.

O compilador C ++ faz essa verificação para você.

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

Este código - muito simplificado - garante que não haja instanciação como esta:Foo foo;

Peter VARGA
fonte
12
A declaração excluída é desnecessária aqui. Ele é excluído automaticamente com qualquer construtor fornecido pelo usuário
Mike Lui
5
Para esclarecer o comentário de @MikeLui, a declaração excluída é desnecessária para o compilador . Existem vários casos em que um código como este deve ser incluído para declarar a intenção a outros programadores .
Jeff G
Junto com a declaração de sua intenção, ele cria um local óbvio para documentar o motivo de sua exclusão na interface pública e, além disso, o erro do compilador será algo curto como "uso de função excluída". Se Footivesse vários construtores, apenas um não padrão, Foo foo;causaria um erro muito mais longo listando todos os construtores implicitamente definidos, protegidos e privados com os quais falhou.
sigma
Eu ainda não entendi como a linha extra com a declaração do construtor que palavra-chave "= delete" declara a intenção da ideia "nenhum construtor padrão" melhor do que ... apenas nenhum construtor padrão? Exemplo: Não quero declarar a variável "a" em meu código - o que é melhor, escrever "// int a; // não há necessidade de definir a variável a" ou simplesmente não escrever nada sobre essa variável no código?
Ezh
2

Eu me encontrei com ctors padrão declarados como 'excluídos' no código-fonte do LLVM (em AlignOf.h, por exemplo). Os modelos de classe associados geralmente estão em um namespace especial chamado 'llvm :: detail'. Acho que todo o propósito ali era que eles considerassem aquela classe apenas como uma classe auxiliar. Eles nunca tiveram a intenção de instanciá-los; apenas para usá-los dentro do contexto de outros modelos de classe com alguns truques de metaprogramação executados em tempo de compilação.

Por exemplo. existe este modelo de classe AlignmentCalcImpl que é usado apenas em outro modelo de classe chamado AlignOf como um parâmetro para o operador sizeof (.). Essa expressão pode ser avaliada em tempo de compilação; e não há necessidade de instanciar o template -> então por que não declarar o ctor default delete para expressar esta intenção.

Mas é apenas minha suposição.

Gybacsi
fonte