c++ - example - std::variant




Como o std:: opcional nunca é "sem valor por exceção"? (2)

"sem valor por exceção" refere-se a um cenário específico em que é necessário alterar o tipo armazenado na variante. Isso requer necessariamente 1) destruir o valor antigo e 2) criar o novo em seu lugar. Se 2) falhar, você não terá como voltar atrás (sem custos indiretos inaceitáveis ​​para o comitê).

optional não tem esse problema. Se alguma operação no objeto contiver uma exceção, que assim seja. O objeto ainda está lá. Isso não significa que o estado do objeto ainda seja significativo - seja qual for a operação de lançamento. Esperemos que a operação tenha pelo menos a garantia básica.

std::variant pode entrar em um estado chamado " sem valor por exceção ".

Pelo que entendi, a causa comum disso é se uma atribuição de movimentação gerar uma exceção. Não é garantido que o valor antigo da variante esteja presente e também não é o novo valor pretendido.

std::optional , no entanto, não possui esse estado. A cppreference faz a afirmação ousada:

Se uma exceção for lançada, o estado de inicialização de * this ... permanecerá inalterado, ou seja, se o objeto contiver um valor, ele ainda contiver um valor, e vice-versa.

Como o std::optional pode evitar se tornar "sem valor por exceção", enquanto o std::variant não é?


optional<T> possui um dos dois estados:

  • um T
  • esvaziar

Uma variant só pode entrar no estado sem valor ao fazer a transição de um estado para outro se a transição ocorrer - porque você precisa recuperar o objeto original e as várias estratégias para isso exigem armazenamento extra 1 , alocação de heap 2 ou estado vazio 3)

Mas para optional , a transição de T para vazio é apenas uma destruição. Então isso só funciona se o destruidor de T jogar, e realmente quem se importa nesse momento. E a transição de vazio para T não é um problema - se isso acontecer, é fácil recuperar o objeto original: o estado vazio está vazio.

O caso desafiador é: emplace() quando já tínhamos um T Precisamos necessariamente ter destruído o objeto original, então o que fazemos se a construção do local for lançada? Com o optional , temos um estado vazio conhecido e conveniente para o qual retornar - então o design é apenas para fazer isso.

problemas da variant de não ter esse estado fácil de recuperar.

1 Como boost::variant2 faz.
2 Como boost::variant faz.
3 Não tenho certeza de uma implementação de variante que faça isso, mas houve uma sugestão de design de que a variant<monostate, A, B> poderia fazer a transição para o estado monostate se monostate um A e a transição para B fosse monostate .





std-variant