Biblioteca de classes genéricas - bugs, descrição, perguntas, recursos de uso e sugestões - página 19
![MQL5 - Linguagem para estratégias de negociação inseridas no terminal do cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
Você está perdendo oportunidades de negociação:
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Registro
Login
Você concorda com a política do site e com os termos de uso
Se você não tem uma conta, por favor registre-se
Afinal, você pode escrever a sua própria especialização de uma função para uma classe.
Você não pode fazer isso sem uma interface.
Não o podes fazer sem uma interface.
O que você não pode fazer sem uma interface? )
Bem, pensem nisso. De qualquer forma, não desarrume o fio, por favor.
Problema
Obviamente, o GetHashCode não pode ser implementado corretamente no ambiente do usuário MQL5. Isto é porque nem todos os objectos podem ser acedidos. E se a implementação funciona bem para membros primitivos como int duplo, etc., para objetos complexos (classes, estruturas e até enumerações) o hash é calculado pelo nome. Se tivermos milhares de CObjects ou mesmo ENUM_something_that, então CHashMap e CHashSet irão degenerar em LinkedList:
Não podemos evitar isto porque tudo o que temos ao nível do utilizador é o nome do objecto:
Assim, os hashes de todos os objetos de tipos complexos são iguais entre si e este código de busca aqui envolve uma enumeração completa da matriz:
Na verdade, isto é tão crítico que se sobrepõe a todo o ponto de usar o genérico na raiz. A questão é que na maioria dos casos você precisa associar ou armazenar objetos complexos: enumerações, estruturas ou classes. Se você precisasse operar com tipos simples, você poderia fazer com algo mais simples.
Para que coleções genéricas funcionem corretamente com objetos de classe, estas classes devem implementar a interface IEqualityComparable, onde os métodos Equals e HashCode são definidos. Isso significa que o usuário deve definir métodos de cálculo de códigos hash por ele mesmo, e essa é a única opção até agora, pois é impossível implementar esses métodos automaticamente, como é feito em .Net, por exemplo, por meio de MQL5.
Para que coleções genéricas funcionem corretamente com objetos de classe, estas classes devem implementar a interface IEqualityComparable, na qual são definidos métodos Equals e HashCode. Isso significa que o usuário tem que definir métodos de cálculo de códigos hash e essa é a única opção até agora, pois é impossível implementar esses métodos automaticamente, como foi feito em .Net, por exemplo, por meio de MQL5.
Roman, esqueceste-te de mencionar que em A MQL5 não tem interfaces. Este artigo irá introduzir o conceito de interfaces na MQL5.
p.s. Mas mesmo que aparecessem interfaces na MQL5, a questão das estruturas e enumerações permaneceria por resolver.
Roman, esqueceste-te de mencionar que em A MQL5 não tem interfaces. Qualquer discussão sobre interfaces na MQL5 de hoje é uma insinuação maliciosa e demagogia.
p.s. Mas mesmo que tivessem surgido interfaces na MQL5, a questão das estruturas e enumerações teria ficado por resolver.
Por enquanto na MQL5 não é possível, em princípio, escrever métodos de modelos que funcionariam para classes, estruturas e enumerações ao mesmo tempo, devido às peculiaridades da transferência de dados.
É disso que estou a falar. Mas o ambiente MQL5 sabe tudo sobre seus objetos! Ele tem apontadores para objetos e conhece todos os identificadores de enums (EnumToString). É por isso que precisamos do GetHashCode como um sistema e função omnívora.
E, finalmente, permitir a herança de múltiplas interfaces. Rewrite Generic para interfaces normais e você terá um ponto doce.
A situação é óbvia: os desenvolvedores de MQ eram tão frequentemente queimados por herança múltipla em C++ que agora temem qualquer manifestação dela. Como resultado, é proposto evitar uma porcaria (herança múltipla) usando outra porcaria: cadeias de herança ridículas.
Você tem que entender que as interfaces não têm nada a ver com herança. Uma interface é uma declaração de que uma classe se compromete a fornecer uma determinada funcionalidade. Se duas classes implementam a mesma funcionalidade, elas não devem herdar uma da outra. Herança = maldade.
Fórum sobre negociação, sistemas de negociação automatizados e testes de estratégia de negociação
Biblioteca de classes genéricas - bugs, descrição, perguntas, peculiaridades de uso e sugestões
Roman Konopelko, 2017.12.18 16:29
1) O factor de crescimento do volume (capacidade) não é igual a 1.2, CPrimeGenerator::O método ExpandPrime é utilizado para calcular o novo volume no CHashMap:
Neste método, o tamanho da colecção antiga é multiplicado por dois, depois para o valor resultante encontramos o mais próximo do número primo superior e devolvemo-lo como o novo volume.
Sobre o valor inicial da capacidade - concordo, é muito pequena.
Mas, por outro lado, há sempre construtores, onde se pode especificar explicitamente a capacidade inicial:
Por isso não vejo muito sentido mudar algo aqui.
Sim, eu estava errado, eu arrependo-me.
Realmente, o fator de incremento de volume (capacidade) para CHashMap é mais de 2.
Obrigado por apontar o erro e pedir desculpas por desperdiçar tempo.
Por outro lado, eu consegui dedicar tempo para estudar a implementação do CPrimeGenerator.
E há algumas sugestões, principalmente para melhorar o desempenho.
1. Eliminar comportamentos ambíguos:
Se passarmos "INT_MAX - 10" como parâmetro ao CPrimeGenerator::ExpandPrime, o resultado "INT_MAX" será devolvido.
Se passarmos "INT_MAX - 10" como parâmetro ao CPrimeGenerator::GetPrime, o mesmo resultado será devolvido: "INT_MAX - 10".
Além disso, em ambos os casos, o valor retornado não é um número primo que induza o usuário em erro.
2. Ao ligar para oGetPrime para números superiores a7199369, a poupança de memória torna-se uma prioridade, mas isso não justifica o relativo mau desempenho e cálculos inúteis.
Sugestão:
- adicionar uma comparação de número com o último valor do arrayCPrimeGenerator::s_primes[] e não realizar enumeração desnecessária de todos os 72 elementos do array.
- Substitua a busca dinâmica por números simples (passa por todos os números em uma linha) por um array de valores pré-definidos comoCPrimeGenerator::s_primes[], mas com incremento linear, não quadrático.
O incremento de valores será de cerca de 1 milhão (um valor semelhante ao incremento de s_primes nos últimos elementos do array).
O número de elementos é de até 3000, os valores variam de 8M a INT_MAX.
A matriz será pesquisada através de uma pesquisa binária de limite superior, o número de iterações necessárias é 12.
3. Ao chamarGetPrime para números inferiores a7199369, o pior caso é uma busca linear de todos os 72 valores do arrayCPrimeGenerator::s_primes[].
A sugestão é:
- reduzir o número de elementos da matriz para 70. (apagando os dois primeiros, ou o primeiro e o último):
- se o valor de entrada for menor ou igual ao 6º valor no novoCPrimeGenerator::s_primes array - então itere os números linearmente (até 6 comparações).
- Caso contrário, use a pesquisa binária de limite superior entre o valor do 7° e 70° array (cerca de 6 iterações).
A idéia é usar a busca linear apenas enquanto não houver perda de desempenho em comparação com a busca binária.
O número sugerido de elementos - 6 é usado como exemplo, na realidade tudo depende da implementação concreta da pesquisa binária de limite superior.
O ganho de desempenho geral devido à baixa intensidade de chamada de uma determinada função pode não ser tão benéfico a ponto de fazer qualquer trabalho para melhorar esta funcionalidade.