É a forte garantia de exceção de segurança com um argumento de passagem por valor que pode causar destruição?

8

Suponha que você tenha um tipo com um destruidor de lançamento e uma função que o receba por valor.
Essa operação pode fornecer algo melhor do que a garantia básica de exceção?
Ou formulado de maneira diferente, pode-se desconsiderar a destruição do argumento que foi passado por valor ao determinar se uma operação possui semântica de confirmação e reversão?

#include <cstdlib>

struct X {
    ~X() noexcept(0) {
        if(rand()%6 == 0) throw 0;
    }
    // some state
};

void update(database db, X arg) noexcept;

X x;
update(db, x);

Pessoalmente, com base na definição da wikipedia

  1. Forte segurança de exceção , também conhecida como semântica de confirmação ou reversão : as operações podem falhar, mas as operações com falha têm garantia de não ter efeitos colaterais; portanto, todos os dados mantêm seus valores originais

Eu não acho que seja útil descrever updatecomo sendo altamente seguro para exceções, mesmo que a função em si não possa ser lançada.

Eu apreciaria alguém que me mostrasse a loucura do meu entendimento atual ou apresentasse um argumento melhor.

Desduplicador
fonte
E se um método da classe lançar e o chamador decidir descartar o objeto? O destruidor ainda fechará a transação?
Robert Harvey
Método em que classe? E fechar qual transação? Desculpe, mas estou confuso agora.
Deduplicator
Bem, a menos que um padrão de lembrança esteja sendo usado ou uma transação de banco de dados esteja envolvida, não vejo como o estado da classe não é perdido quando o objeto é descartado, a menos que você esteja dizendo que é uma classe sem estado.
Robert Harvey
2
A pergunta foi inspirada no argumento aqui: chat.stackexchange.com/rooms/32049/… chat.stackexchange.com/rooms/32061/…
Deduplicator
4
Em geral, um destruidor de arremesso é um veneno completo para todas as garantias de segurança de exceção. Isso fica mais difícil por ordens de magnitude.
Sebastian Redl

Respostas:

7

Não tenho muita certeza em retrospecto, mas se updateera genérico ou Xabstrato (ex: clonado e destruído) - ou seja, se updatenão pudesse saber nada de concreto X, então, para todos os fins práticos, eu o descreveria como um forte garantia de exceção-segurança. No mínimo, isso é o mais próximo de uma forte garantia de exceção de segurança que você jamais terá em um contexto abstrato sem radiografar um tipo de dados.

No entanto, Xé concreto, o que torna essa pergunta muito mais confusa. Ainda estou tentado a dizer que update"tem uma forte garantia de segurança de exceção", pois está fazendo tudo o que pode fazer para cumpri-la. Isso soa como uma conversa maluca? Faz comigo, mas na verdade não posso melhorar muito.

Especialmente no contexto de um ambiente de equipe em que um autor implementa updatee o outro implementa X, nada poderia fornecer uma forte garantia de exceção-segurança, pois Xpoderia ser modificado de maneira a quebrar a garantia de maneiras completamente fora do controle de update. Para fins práticos, acho que, se updatefizer tudo o que puder e puder reverter seus próprios efeitos colaterais em caminhos excepcionais, praticamente fornecerá uma forte garantia de segurança de exceção.

Caso contrário, a forte garantia de segurança de exceção se tornará algo impraticável para fornecer em muitos cenários. As coisas podem mudar fora do controle da função. As coisas podem ser abstratas de maneiras além do conhecimento da função. Toda a garantia seria quase impossível de fornecer em qualquer lugar. Nesse caso, poderíamos dizer que a forte garantia de exceção updatepropaga a responsabilidade Xde cumprir, ou updateé necessário saber como Xserá implementado o tempo todo? Eu não sei. Isso é tudo muito impraticável de qualquer maneira, e eu não gosto de impraticabilidades.

Então, eu vou com o bruto, sim, " updateé seguro para exceções, mas Xfoi fubar e estragou tudo. Não é update'sculpa, pelo menos. Não processe o autor da atualização! Sue the author of X!" . Eu gostaria de descrever Xcomo simplesmente sendo fubar aqui e updatecomo possivelmente fornecendo uma forte garantia de segurança de exceção, que está sendo ferrada pelo fato de Xser fubar. Ou seja, a menos que haja um entendimento muito difícil no nível da interface que o X'sdestruidor foi projetado para lançar, nesse caso, não tenho idéia de como descrevê-lo, exceto como um "grande problema". Acho que precisamos de algumas impressões e isenções de responsabilidade para fornecer essas garantias.atualização fornece uma forte garantia de exceção-segurança, desde que [...]. Nenhum reembolso se este não for o caso!

Isso é como uma pergunta filosófica para mim, interessante de se pensar, mas talvez uma sem resposta perfeita. E o que são garantias, afinal? Podemos garantir alguma coisa? Posso garantir que beber cerveja me deixe bêbado e isso possa parecer verdadeiro o tempo todo, mas e se um extraterrestre intervir e usar algum tipo de tecnologia alienígena que me deixe sóbrio, por mais que eu beba? Não posso garantirque isso não vai acontecer. Só posso dizer que isso é altamente improvável e que, se esse evento acontecer, eu ficaria impotente contra ele. Eu fiz a minha parte. Eu bebi minha cerveja. Eu deveria ficar bêbado. Eu garanto isso fortemente. Mas não é certo. Sempre há alguma probabilidade, embora astronomicamente remota, de que a garantia não seja verdadeira. E quanto à segurança da linha? Bem, e se a espaçonave alienígena aparecer e zapear nosso hardware e reorganizar as instruções na memória, de modo que uma função formalmente segura para threads não seja mais segura para threads em tempo de execução? Não posso garantir que isso não aconteça. Mas eu garanto a segurança da linha, independentemente, mesmo sem entrar em detalhes sobre naves espaciais alienígenas, porque isso faz as pessoas se sentirem bem e tranqüilizadas, e o que estou dizendo é que eu '

Descartes disse uma vez: "Penso que sim". Como ele sabe? E se ele não estiver? Ele poderia ser um "não sou", mas talvez "não" possa "pensar". Eu nem sei se eu existo. O que significa pensar, afinal? É como uma palavra que as pessoas usam para descrever algum processo que parece continuar introspectivamente e parece que nós, que nem existimos, estamos tomando decisões.

E se todos nós somos apenas bits e bytes em alguma máquina? Como aquela loira ou morena na Matrix. A propósito, como uma loira ou especialmente morena pode ser armazenada em um fluxo tão pequeno de caracteres? Eles são como UTF2048? Era algum tipo de fluxo alienígena de personagens, mas não parecia haver muitos personagens únicos. Talvez seja algum tipo de chamada de função. De qualquer forma, não tenho certeza se podemos garantir alguma coisa. É tudo relativo ao que acreditamos ser verdade.


fonte
5
"Portanto," segurança de exceção "de qualquer tipo e" destruidor de arremessos "provavelmente nunca devem ser combinados na mesma frase. Eles são, para todos os efeitos práticos, mutuamente exclusivos". +1, não posso argumentar com essa lógica. Se você acha que pode, não está sendo lógico.
Não vejo como isso responde à pergunta original. O problema aqui é que o arg destruirá exatamente na saída da função. A função não terá chance de capturar isso. Se a função tiver feito algo, não será possível revertê-la.
Nir Friedman
2
Sim, essa é a conclusão correta, não se torna menos correta por ser desagradável. No caso do vetor, é ilegal que o destruidor do tipo contido seja lançado: stackoverflow.com/questions/26902006/… . Entendo sua abordagem "orientada para a equipe", mas, francamente, ela é vista de uma perspectiva de justiça, e não de correção.
Nir Friedman
2
Minha interpretação preferida é simplesmente que jogar um destruidor é um comportamento indefinido, e que exceção garante uma função é tudo baseado na suposição implícita de que nenhum comportamento indefinido ocorre (de fato, tudo na linguagem faz essa suposição). Se o comportamento indefinido puder incluir a formatação do disco rígido, certamente poderá violar as garantias de exceção corretas de qualquer outra coisa no programa.
Ixrec
1
@Ixrec Essa pode ser sua interpretação preferida, mas jogar de um destruidor geralmente não é algo comum, isso é simplesmente um fato.
Nir Friedman
-1

Tecnicamente falando, talvez possa fornecer a forte garantia de exceção. Significativamente, ele só pode fornecer a forte garantia de exceção no caso trivial em que não faz nada.

Herb Sutter fala sobre um caso semelhante (e mais intuitivo) em que uma função recebe um argumento por valor que possui um construtor de cópias de lançamento. Você pode rotular essa função como exceto. Tecnicamente, a exceção ocorre na "cola" entre o código de chamada e a função chamada, não dentro da própria função. Esse é o caso aqui também. Como a exceção não é tecnicamente lançada dentro da atualização, você pode (talvez) argumentar que a atualização em si não gera o erro e, portanto, pode oferecer uma forte garantia de exceção.

Na prática, se a atualização fizer alguma coisa, chamá-la (e não fazer mais nada) pode levar à mudança do estado do mundo e ao lançamento de uma exceção, quebrando a forte garantia de exceção.

Nir Friedman
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
maple_shaft