Condições para geração automática de operador padrão / copiar / mover e copiar / mover atribuição?


Respostas:


136

A seguir, "gerado automaticamente" significa "declarado implicitamente como padrão, mas não definido como excluído". Há situações em que as funções-membro especiais são declaradas, mas definidas como excluídas.

  • O construtor padrão é gerado automaticamente se não houver construtor declarado pelo usuário (§12.1 / 5).
  • O construtor de cópia é gerado automaticamente se não houver construtor de movimentação declarado pelo usuário ou operador de atribuição de movimentação (porque não há construtores de movimentação ou operadores de atribuição de movimentação no C ++ 03, isso simplifica para "sempre" no C ++ 03) ( §12.8 / 8).
  • O operador de atribuição de cópia é gerado automaticamente se não houver construtor de movimentação declarado pelo usuário ou operador de atribuição de movimentação (§12.8 / 19).
  • O destruidor é gerado automaticamente se não houver destruidor declarado pelo usuário (§12.4 / 4).

Apenas C ++ 11 e posterior:

  • O construtor de movimentação é gerado automaticamente se não houver construtor de cópia declarado pelo usuário, operador de atribuição de cópia ou destruidor e se o construtor de movimentação gerado for válido (§12.8 / 10).
  • O operador de atribuição de movimentação é gerado automaticamente se não houver construtor de cópia declarado pelo usuário, operador de atribuição de cópia ou destruidor e se o operador de atribuição de movimentação gerado for válido (por exemplo, se não for necessário atribuir membros constantes) (§12.8 / 21)

9
Um destruidor herdado conta? Quero dizer, digamos que tenho uma classe base com um destruidor virtual vazio. Isso impede a criação de construtores de movimentação nas subclasses? Se a resposta for sim, ajudará se eu definir um construtor de movimento na classe base?
— Kamilk

10
Eu acho que você deve mencionar talvez que ter constmembros na classe irá impedir o construtor de ser auto-gerado ...
— nonsensickle

"Há situações em que as funções especiais de membro são declaradas, mas definidas como excluídas." consulte onde você tem, por exemplo, membros const ou de referência para onde a mudança será impossível? Não, não pode ser, porque a cópia será aplicada.
— towi

Eu sei que é restrito o envio de hiperlinks neste fórum. Mas também é um bom artigo - cplusplus.com/articles/y8hv0pDG
— bruziuz 12/12/16

Observe que, como padrão, um construtor de cópias implicitamente padronizado " é preterido se a classe tiver um operador de atribuição de cópia declarada pelo usuário ou um destruidor declarado pelo usuário " ( 12.8 Copiando e movendo objetos de classe [class.copy] ).
— 29517 sigy

98

Achei o diagrama abaixo muito útil.

Regras C ++ para construtores automáticos e operadores de atribuição de Sticky Bits - Tornando-se uma regra do herói zero


Lindo. A que se refere "independente"? Independente do que?
— towi

8
O copiador / tarefa é 'independente' um do outro. Se você escrever apenas um, o compilador fornecerá o outro. Por outro lado, se você fornecer um controlador de movimentação ou uma atribuição de movimentação, o compilador não fornecerá o outro.
— Marco M.

Gostaria de saber qual é o motivo por trás das operações de cópia serem independentes. Razões históricas podem ser? ou o fato de que a cópia não modifica seu destino, mas a mudança muda?
— RaGa__M 5/17/17

@Explorer_N Sim, compatibilidade com versões anteriores, motivos históricos. Foi uma escolha ruim de design há muito tempo, então agora há uma necessidade de boas práticas como a "regra dos três" (defina todas as três ou nenhuma: construtor de cópias, operador de atribuição de cópias e muitas vezes destruidor) para evitar erros difíceis de encontrar.
— atablash

@MarcoM., Até onde eu entendi, a condição "Se você escreve ..." inclui os dois casos de definir a função de membro especial como = delete(óbvio) ou = default(menos óbvio para mim). Estou certo?
— Enrico Maria De Angelis

2

Rascunho padrão C ++ 17 N4659

Para uma referência rápida entre padrões, consulte as seções "Declaradas implicitamente" das seguintes entradas de preferência:

Naturalmente, a mesma informação pode ser obtida no padrão. Por exemplo, em rascunho padrão C ++ 17 N4659 :

15.8.1 "Copiar / mover construtores" diz para o construtor de cópias:

6 Se a definição de classe não declarar explicitamente um construtor de cópia, um não-explícito será declarado implicitamente. Se a definição de classe declara um construtor de movimentação ou um operador de atribuição de movimentação, o construtor de cópia declarado implicitamente é definido como excluído; caso contrário, é definido como padrão (11.4). O último caso será preterido se a classe tiver um operador de atribuição de cópia declarada pelo usuário ou um destruidor declarado pelo usuário.

e para mover construtor:

8 Se a definição de uma classe X não declarar explicitamente um construtor de movimento, um não explícito será implicitamente declarado como padrão se e somente se

  • (8.1) - X não possui um construtor de cópias declarado pelo usuário,

  • (8.2) - X não possui um operador de atribuição de cópia declarado pelo usuário,

  • (8.3) - X não possui um operador de atribuição de movimentação declarado pelo usuário e

  • (8.4) - X não possui um destruidor declarado pelo usuário.

15.8.2 "Copiar / mover operador de atribuição" diz para atribuição de cópia:

2 Se a definição de classe não declarar explicitamente um operador de atribuição de cópia, um será declarado implicitamente. Se a definição de classe declara um construtor de movimentação ou um operador de atribuição de movimentação, o operador de atribuição de cópia declarado implicitamente é definido como excluído; caso contrário, é definido como padrão (11.4). O último caso será descontinuado se a classe tiver um construtor de cópias declarado pelo usuário ou um destruidor declarado pelo usuário.

e para atribuição de movimento:

4 Se a definição de uma classe X não declarar explicitamente um operador de atribuição de movimentação, um será implicitamente declarado como padrão se e somente se

  • (4.1) - X não possui um construtor de cópias declarado pelo usuário,
  • (4.2) - X não possui um construtor de movimentação declarado pelo usuário,
  • (4.3) - X não possui um operador de atribuição de cópia declarado pelo usuário e
  • (4.4) - X não possui um destruidor declarado pelo usuário.

15.4 "Destruidores" diz isso para destruidores:

4 Se uma classe não tiver um destruidor declarado pelo usuário, um destruidor é declarado implicitamente como padrão (11.4). Um destruidor implicitamente declarado é um membro público interno de sua classe.

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.