MQL5 O compilador não faz distinção entre uma classe e um ponteiro para ela - página 13

 
Ilya Malev:

Não é a mesma coisa no MCL que no C++. Aqui um ponteiro não é um tipo de dado separado, portanto ambos são objetos, e uma variável contém seu cabo.

certo?

// тот же класс А что был выше

A a; // будет создан автообъект с реальным выделением памяти и инициализацией. 'a' является указателем со статусом POINTER_AUTOMATIC

A* pA; // память под объект не выделена, объекта нет. pA является указателем со статусом POINTER_INVALID или POINTER_DYNAMIC?

Mas não posso dizer com certeza qual o status que o ponteiro recebe após a criação:POINTER_INVALID ou POINTER_DYNAMIC. Em teoria, deve ser POINTER_INVALIDO até receber o endereço de novo.

 
Ilya Malev:

Ou seja, declarar

E você terá exatamente o mesmo "auto-objeto", mas você mesmo terá que apagá-lo.

Isso não é automático...

 
SemenTalonov:

Não posso dizer que status o ponteiro recebe após a criação,POINTER_INVALID ou POINTER_DYNAMIC. Em idéia, deve ser POINTER_INVALIDO até que novos obtenham o endereço.

Isso é correto, o status será POINTER_INVALIDO. Mas as variáveis a e pA são do mesmo tipo. Apenas a é uma constante, o construtor é chamado para a criação e o destruidor ao sair do bloco, enquanto pA é acessado aleatoriamente e o construtor e o destruidor são chamados arbitrariamente.

Uma variável declarada sem * não pode obter o status POINTER_INVALID sem truques especiais, isto também é verdade, mas não porque as variáveis são de tipos diferentes, mas porque o compilador controla bem as chamadas do construtor e do destruidor, e proíbe que ele atribua outro valor.

E como as variáveis são essencialmente do mesmo tipo, não há lógica para acessar métodos de classe através deles de forma diferente

 
Ilya Malev:

Isto é correto, o status será POINTER_INVALIDO. Mas as variáveis a e pA são do mesmo tipo. Apenas um é constante e construtor é chamado na criação, e destruidor na saída do bloco, e pA é com acesso aleatório, e com chamadas aleatórias de construtor e destruidor.

Portanto, todos os problemas só vêm do fato de que você precisa distingui-los. Isto é, um ponteiro requer uma atitude mais responsável (oDINÂMICO).

 
SemenTalonov:

A única razão para o problema é que eles devem ser distinguidos. Isto é, um ponteiro requer uma atitude mais responsável (oDINÂMICO).

Na minha opinião, o objetivo do OOP é apenas que as referências a objetos possam ser passadas e armazenadas, e diferentes classes com diferentes comportamentos possam ser escritas nelas. Começando a armazenar uma referência a um "auto-objeto" sem sequer tocar no polimorfismo, você já perde toda sua distinção (já que não há variáveis de usuário do tipo A&)

 
Ilya Malev:

Uma variável declarada sem * não pode receber o status POINTER_INVALID sem truques especiais, isto também é verdade, mas não porque as variáveis são de tipos diferentes, mas porque o compilador controla bem as chamadas do construtor e do destruidor, e proíbe atribuir-lhe um valor diferente.

Exatamente. O ponteiro auto-objeto não mudará seu status, enquanto que o ponteiroPOINTER_DYNAMIC pode se tornar não válido a qualquer momento da execução do programa. As razões não são tão importantes quanto a possibilidade de um evento desse tipo em si.

 
SemenTalonov:

Exatamente. O ponteiro auto-objeto não mudará seu status, enquanto oponteiro POINTER_DYNAMIC pode se tornar inválido enquanto o programa estiver em execução. As razões não são tão importantes quanto a possibilidade de um evento desse tipo em si.

Há uma cura excelente e segura para isso:

class A{~A(){}};

void OnStart()
 {
  A*a=new A;
  delete a; // oops =))
 };
Bem, acho que os programadores devem observar o tempo de vida dos objetos e as próprias formas de acesso às variáveis enquanto a arquitetura pensada desde o início minimizará os erros em um ou dois anos depois de escrever o código...
 
Na verdade, a vida útil do objeto deve corresponder à vida útil dos ponteiros "vivos". É claro que o objeto dinâmico POINTER_DYNAMIC também é uma solução a meio caminho, o que cria problemas para uma codificação irrefletida. Mas POINTER_AUTOMÁTICO também não me dá aquela escalabilidade que eu preciso para lidar corretamente com objetos. Precisamos que seja assim - se nenhuma indicação de objeto foi criada ao sair do bloco, exceto a autovariável onde ela foi criada, então exclua o objeto. Se foram recebidas referências fora do bloco atual - não exclua o objeto enquanto essas referências ainda existirem. Então haverá escalabilidade e o codificador não terá que assistir à exclusão por si só o tempo todo... (por exemplo, se você agora escrever A* a = novo A; e depois a = novo A novamente, o primeiro objeto será perdido para sempre e é garantido que haverá erros de vazamento de memória nos registros ao sair do programa. E onde o célebre otimizador de código olha para isso?)
 
Ilya Malev:
Essencialmente, a vida útil de um objeto deve corresponder à vida útil dos ponteiros "vivos" para ele. Naturalmente, o objeto dinâmico do tipo mcl POINTER_DYNAMIC é também uma solução semi-opcional que causa problemas quando a codificação não é muito eficiente. Mas POINTER_AUTOMÁTICO também não me dá aquela escalabilidade que eu preciso para lidar corretamente com objetos. Precisamos que seja assim - se nenhuma indicação de objeto foi criada ao sair do bloco, exceto a autovariável onde ela foi criada, então exclua o objeto. Se foram recebidas referências fora do bloco atual - não exclua o objeto enquanto essas referências ainda existirem. Então haverá escalabilidade e o codificador não terá que assistir à exclusão por si só o tempo todo... (por exemplo, se você agora escrever A* a = novo A; e depois a = novo A novamente, o primeiro objeto será perdido para sempre e é garantido que haverá erros de vazamento de memória nos registros ao sair do programa. E onde o célebre otimizador de código olha para isso?)

Isso também foi uma surpresa e tanto. Afinal, ele conhece exatamente cada byte que escapou, mas não quer liberá-lo. Então não assiste a dino-pólos no momento? Ela simplesmente conta a diferença entre a memória solicitada e a memória liberada no final.

E os indicadores de vida útil e vazios/perdidos são apenas um dos problemas. Quando por engano (por exemplo, o compilador não deve ter permitido compilar tal código), em vez do ponteiro esperado, você pode obter uma cópia de um objeto por ponteiro, o que, por sua vez, pode apontar para nenhum lugar). Bem, você mesmo já escreveu sobre operações de comparação. Tudo aí também está muito implícito.

 
SemenTalonov:

1. Isso também foi uma surpresa e tanto. Afinal, ele conhece exatamente cada byte que escapou e não quer liberá-lo. Então não assiste a dino-pólos no momento? Ela apenas conta a diferença entre a memória solicitada e a memória liberada no final.

E os indicadores de vida útil e vazios/perdidos são apenas um dos problemas.

1. Não realmente, escrever um simples GC para objetos dinâmicos seria canja para os desenvolvedores, mas eles deixaram essas mensagens de propósito, para que os codificadores pudessem ver que eles têm uma falha em seu programa. Porque seus objetos dinâmicos são tão semi-C# (não sou especialista nisso, mas pelo que ouvi dizer) - como se os objetos se comportassem da mesma maneira (sem indicações, mas todos são objetos), e nenhum subsistema elaborado para eles foi desenvolvido.

2. Bem, sim, claro, se as variáveis do objeto fossem do mesmo tipo (ou seja: apagadas não automaticamente ou independentemente, mas por coletor de lixo incorporado quando não há referências a elas), então todas as referências a elas seriam exatamente as mesmas.