O que significa "padrão" após a declaração de função de uma classe?


221

Eu já vi defaultusado ao lado de declarações de função em uma classe. O que isso faz?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

26
O que o "&" que precede o "=" nas declarações do operador de atribuição faz?
dshin

6
@dshin Esta é uma qualificação prévia de uma função de membro .
Kane

Respostas:


249

É um novo recurso do C ++ 11 .

Isso significa que você deseja usar a versão gerada pelo compilador dessa função, para não precisar especificar um corpo.

Você também pode usar = deletepara especificar que não deseja que o compilador gere essa função automaticamente.

Com a introdução de construtores de movimentação e operadores de atribuição de movimentação, as regras para quando versões automáticas de construtores, destruidores e operadores de atribuição são geradas se tornaram bastante complexas. Usar = defaulte = deletefacilitar as coisas, pois você não precisa se lembrar das regras: basta dizer o que deseja que aconteça.


17
= deleteé mais forte: significa que é proibido usar essa função, embora ela ainda participe da resolução de sobrecarga.
Deduplicator

2
Mas, se queremos usar a definição de geração do compilador, não devemos pular a gravação dessa função em vez de "primeiro escrevê-la e depois atribuí-la ao padrão"?
Mayank Jindal

47

Este é um novo recurso C ++ 0x que informa ao compilador para criar a versão padrão do respectivo construtor ou operador de atribuição, ou seja, aquele que apenas executa a ação de copiar ou mover para cada membro. Isso é útil porque o construtor de movimentação nem sempre é gerado por padrão (por exemplo, se você tem um destruidor personalizado), diferentemente do construtor de cópia (e da mesma forma para a atribuição), mas se não houver nada não trivial para escrever, é melhor deixar o compilador lidar com isso do que soletrar você mesmo a cada vez.

Observe também que um construtor padrão não seria gerado se você fornecer outro construtor não padrão. Se você ainda deseja o construtor padrão também, pode usar esta sintaxe para que o compilador faça um.

Como outro caso de uso, há várias situações nas quais um construtor de cópias não seria gerado implicitamente (por exemplo, se você fornecer um construtor de movimentação personalizado). Se você ainda deseja a versão padrão, pode solicitá-la com esta sintaxe.

Consulte a Seção 12.8 da norma para obter detalhes.


5
Embora não seja apenas para construtores e atribuições, também se aplica a operator new/new[], operator delete/delete[]e suas sobrecargas.
Sebastian Mach

21

É novo no C ++ 11, veja aqui . Pode ser bastante útil se você definiu um construtor, mas deseja usar padrões para os outros. Antes do C ++ 11, você teria que definir todos os construtores depois de definir um, mesmo que sejam equivalentes aos padrões.

Observe também que, em determinadas situações, é impossível fornecer um construtor padrão definido pelo usuário que se comporte da mesma forma que o compilador sintetizou um na inicialização padrão e no valor . defaultpermite recuperar esse comportamento.


5
em relação ao segundo parágrafo, você pode fornecer um exemplo?
John Smith

11

Outro caso de uso que não vejo mencionado nessas respostas é que ele permite alterar facilmente a visibilidade de um construtor. Por exemplo, talvez você queira que uma classe de amigo possa acessar o construtor de cópias, mas não deseja que ela esteja disponível ao público.


1

Rascunho padrão C ++ 17 N4659

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Funções explicitamente padronizadas":

1 Uma definição de função do formulário:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

é chamada de definição explicitamente padronizada. Uma função explicitamente inadimplente deve

  • (1.1) - ser uma função membro especial,

  • (1.2) - tem o mesmo tipo de função declarada (exceto para possíveis qualificadores ref diferentes e exceto que, no caso de um construtor de cópias ou operador de atribuição de cópias, o tipo de parâmetro pode ser "referência a não-const T", onde T é o nome da classe da função membro) como se tivesse sido implicitamente declarado, e

  • (1.3) - não possui argumentos padrão.

2 Uma função explicitamente padronizada que não é definida como excluída pode ser declarada constexpr apenas se tivesse sido implicitamente declarada como constexpr. Se uma função é explicitamente padronizada em sua primeira declaração, ela é considerada implicitamente constexpr se a declaração implícita for.

3 Se uma função explicitamente padronizada for declarada com um noexcept-specifier que não produz a mesma especificação de exceção que a declaração implícita (18.4), então

  • (3.1) - se a função for explicitamente padronizada em sua primeira declaração, ela será definida como excluída;

  • (3.2) - caso contrário, o programa está mal formado.

4 [Exemplo:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

- exemplo final]

5 Funções explicitamente padronizadas e funções declaradas implicitamente são chamadas coletivamente de funções padrão, e a implementação deve fornecer definições implícitas para elas (15.1 15.4, 15.8), o que pode significar defini-las como excluídas. Uma função é fornecida pelo usuário se for declarada pelo usuário e não for explicitamente padronizada ou excluída em sua primeira declaração. Uma função explicitamente padronizada fornecida pelo usuário (ou seja, explicitamente padronizada após sua primeira declaração) é definida no ponto em que é explicitamente padronizada; se tal função estiver implicitamente definida como excluída, o programa será mal formado. [Nota: Declarar uma função como padrão após sua primeira declaração pode fornecer execução eficiente e definição concisa enquanto permite uma interface binária estável para uma base de código em evolução. - nota final]

6 [Exemplo:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

- exemplo final]

É claro que a questão é quais funções podem ser declaradas implicitamente e quando isso acontece, que expliquei em:

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.