mql5: A função ZeroMemory não pode ser utilizada para este objecto
Mas porque é que o compilador mostra este erro não num local onde aZeroMemory é utilizada, mas num local onde a classe é definida? É confuso. Por exemplo, ao copiar um objecto que contém itens que não podem ser copiados, o erro ocorre exactamente na linha com a cópia e não algures dentro da classe.
Chegados ao lado prático de tudo isto, já me deparei com um problema. O código estava a utilizar objectos estáticos. Depois decidi substituir algumas delas por outras dinâmicas. Como resultado, as operações de comparação e atribuição começaram a funcionar de forma bastante diferente. E este problema era difícil de detectar porque o programa continua a compilar e a funcionar normalmente, mas não da forma que deveria.
Não compreendi imediatamente o problema
class B {};
class A {
public:
booloperator !=( A* a ) { Print( __FUNCTION__ ); return ( true ); }
booloperator !=( B* b ) { Print( __FUNCTION__ ); return ( false ); }
booloperator >>( A* a ) { Print( __FUNCTION__ ); return ( true ); }
booloperator +( A* a ) { Print( __FUNCTION__ ); return ( false ); }
booloperator !() { Print( __FUNCTION__ ); return ( true ); }
};
voidOnStart()
{
A *a = new A;
B *b = new B;
if ( a != a ) Print( "1" );
if ( a != b ) Print( "2" );
if ( a >> a ) Print( "3" );
if ( !a ) Print( "4" );
delete( a );
delete( b );
}
A partir disto pode ver que (a != a) leva à comparação de apontadores enquanto (a >> a) leva ao operador de chamada >>( A* )
Há uma contradição.
Não pode alterar o comportamento de (a >> a) como outros operadores sobrecarregados (excepto para == e !=) porque tornará impossível a seguinte construção, uma vez que não pode regressar (A) mas só pode regressar (A*).
class A {
public:
A *operator >>( string str ) { return ( GetPointer( this ) ); }
};
voidOnStart()
{
A *a = new A;
a << "1234" << "мы" << "всю ночь" << "тусили"; //множественное применение оператора <<
}
Também será impossível utilizar plenamente operadores sobrecarregados porque não existe uma operação de conversão de ponteiro para objecto (*a)
A única coisa a fazer é alterar o (== e !=) comportamento
Para comparar apontadores (== e !=) entre si e com o número zero (porque outras operações de ponteiro não têm significado), deve-se introduzir uma função especial como (GetPointer) ou especificar explicitamente uma conversão de tipo para o compilador
voidOnStart()
{
A *a = new A;
B *b = new B;
if ( ulong(a) != ulong(b) ) Print( "2" ); //хочу сравнить указатели
if ( a != b ) Print( "2" ); //хочу вызвать operator !=( B* )
}
Assim, a possibilidade de utilização plena de operadores sobrecarregados será preservada e a contradição acima mencionada será eliminada
A única excepção razoável à regra geral deve permanecer operador=() porque
class A {
public:
A *operator =( A* a ) { return ( GetPointer( this ) ); }
};
voidOnStart()
{
A *a = new A;
a = a; //не должно трактоваться компилятором как вызов operator=( A* ),
// а должно остаться как присваивание указателю значения
}
E, claro, a proposta de utilizar (*a) pelo menos para os operadores - voltar à notação C++
class A {
public:
booloperator !=( A* a ) { Print( __FUNCTION__ ); return ( true ); }
};
voidOnStart()
{
A *a = new A;
if ( a != a ) Print( 1 ); //сравнение указателейif ( *a != *a ) Print( 2 ); //вызов operator !=( A* )
}
eliminaria todas as contradições de uma só vez.
Correcção: na verdade, as contradições são eliminadas apenas parcialmente, porque tal notação (*a) não resolve o problema da utilização múltipla de operadores (que agora funciona com sucesso com todos os operadores, excepto == e !=) - por isso a melhor forma de comparar apontadores entre si sobre igualdade/inequalidade continua a utilizar uma função especial - ou conversão explícita para o tipo ulong
class A {
public:
A( int a1 ) : a3( a1 ) { }
staticint a2;
int a3;
};
int A::a2 = 1;
voidOnStart()
{
int b = A::a2; //нормально
A t1( b ); //нормально
A t2( A::a2 ); //ошибка компиляции
A* t3 = new A( A::a2 ); //нормально
}
se um argumento de membro estático de um construtor (excepto novo)
Continuando o tema sobre apontadores, seria bom acrescentar ao operador padrão MQL um apontador'&', seria muito mais conveniente e compacto do que o pesado GetPointer.Assim, tendo * e & operadores no nosso arsenal, podemos definir explicitamente as operações necessárias:
if (&a==&b) Print("Указатели равны");
if (*a==*b) Print("Объекты равны");
E há mais sobre este ampersand. MQL carece de referência a variáveis, especialmente tendo em conta o uso limitado de apontadores (apenas para objectos de classe). A função requer frequentemente acesso a um elemento de estrutura profundamente aninhado ou a uma matriz multidimensional. Tenho de escrever o caminho completo para ele cada vez, o que torna o código muito pesado.Pode-se simplificar as coisas criando uma referência e por vezes basta "mudar" o nome de uma variável localmente por conveniência. No entanto, o que estou a explicar aqui? Toda a gente já sabe como é conveniente usar referências, mas agora é preciso usar #define em vez disso, o que certamente não é bom.
E também precisamos da capacidade de passar o resultado de uma função por referência, ou seja, double& Func() { } { }
Mantendo o tema dos apontadores, seria bom acrescentar à MQL um operador padrão de tomar um apontador'&', seria muito mais conveniente e compacto do que o pesado GetPointer.Assim, tendo os * e & operadores, podemos definir sem ambiguidade as operações necessárias:
Adoptar apenas (*a) para se referir às funções dos membros não dá quaisquer vantagens claras, mas em vez disso torna impossível a utilização dos operadores de uma forma simples e clara.
class A {
public:
A *operator >>( string str ) { Print( __FUNCTION__); return ( GetPointer( this ) ); }
};
voidOnStart()
{
A *a = new A;
a << "1234" << "мы" << "всю ночь" << "тусили"; //простая и понятная запись
Tente reescrevê-lo tendo em conta a sua sugestão
voidOnStart()
{
A *a = new A;
*(*(*(*a << "1234") << "мы") << "всю ночь") << "тусили"; //запутанная запись
}
Não se pode usar o objecto em si em vez do ponteiro porque o operador <<(...) só pode devolver um ponteiro ao objecto.
Que operações com apontadores não têm sentido? - Apenas comparação entre si e com um número - por isso devemos negligenciá-los e colocá-los numa função especial (por exemplo, bool ComparePointer( a,b)) para preservar a possibilidade de utilização múltipla de operadores sem os quais o próprio operador se sobrecarrega perde o seu significado crucial.
Ao testar o Expert Advisor, ele gera um erro
lucro takeprofit inválido para a função OrderSend
Erro de encomendaEnviar 4107
Como posso corrigi-lo sem entrar no código?
A função ZeroMemory não pode ser utilizada para este objecto
Mas porque é que o compilador mostra este erro não num local onde aZeroMemory é utilizada, mas num local onde a classe é definida? É confuso. Por exemplo, ao copiar um objecto que contém itens que não podem ser copiados, o erro ocorre exactamente na linha com a cópia e não algures dentro da classe.
Chegados ao lado prático de tudo isto, já me deparei com um problema. O código estava a utilizar objectos estáticos. Depois decidi substituir algumas delas por outras dinâmicas. Como resultado, as operações de comparação e atribuição começaram a funcionar de forma bastante diferente. E este problema era difícil de detectar porque o programa continua a compilar e a funcionar normalmente, mas não da forma que deveria.
Não compreendi imediatamente o problema
A partir disto pode ver que (a != a) leva à comparação de apontadores enquanto (a >> a) leva ao operador de chamada >>( A* )Há uma contradição.
Não pode alterar o comportamento de (a >> a) como outros operadores sobrecarregados (excepto para == e !=) porque tornará impossível a seguinte construção, uma vez que não pode regressar (A) mas só pode regressar (A*).
Também será impossível utilizar plenamente operadores sobrecarregados porque não existe uma operação de conversão de ponteiro para objecto (*a)
A única coisa a fazer é alterar o (== e !=) comportamento
Para comparar apontadores (== e !=) entre si e com o número zero (porque outras operações de ponteiro não têm significado), deve-se introduzir uma função especial como (GetPointer) ou especificar explicitamente uma conversão de tipo para o compilador
Assim, a possibilidade de utilização plena de operadores sobrecarregados será preservada e a contradição acima mencionada será eliminada
A única excepção razoável à regra geral deve permanecer operador=() porque
eliminaria todas as contradições de uma só vez.
Correcção: na verdade, as contradições são eliminadas apenas parcialmente, porque tal notação (*a) não resolve o problema da utilização múltipla de operadores (que agora funciona com sucesso com todos os operadores, excepto == e !=) - por isso a melhor forma de comparar apontadores entre si sobre igualdade/inequalidade continua a utilizar uma função especial - ou conversão explícita para o tipo ulong
isto está bem, e isto
erro de compilaçãoContinuando o tema sobre apontadores, seria bom acrescentar ao operador padrão MQL um apontador'&', seria muito mais conveniente e compacto do que o pesado GetPointer.Assim, tendo * e & operadores no nosso arsenal, podemos definir explicitamente as operações necessárias:
E há mais sobre este ampersand. MQL carece de referência a variáveis, especialmente tendo em conta o uso limitado de apontadores (apenas para objectos de classe). A função requer frequentemente acesso a um elemento de estrutura profundamente aninhado ou a uma matriz multidimensional. Tenho de escrever o caminho completo para ele cada vez, o que torna o código muito pesado.Pode-se simplificar as coisas criando uma referência e por vezes basta "mudar" o nome de uma variável localmente por conveniência. No entanto, o que estou a explicar aqui? Toda a gente já sabe como é conveniente usar referências, mas agora é preciso usar #define em vez disso, o que certamente não é bom.
E também precisamos da capacidade de passar o resultado de uma função por referência, ou seja, double& Func() { } { }
O Facebook assistiu recentemente ao surgimento de retroligações de posts de blogs:
Mantendo o tema dos apontadores, seria bom acrescentar à MQL um operador padrão de tomar um apontador'&', seria muito mais conveniente e compacto do que o pesado GetPointer.Assim, tendo os * e & operadores, podemos definir sem ambiguidade as operações necessárias:
Adoptar apenas (*a) para se referir às funções dos membros não dá quaisquer vantagens claras, mas em vez disso torna impossível a utilização dos operadores de uma forma simples e clara.
Tente reescrevê-lo tendo em conta a sua sugestão
Não se pode usar o objecto em si em vez do ponteiro porque o operador <<(...) só pode devolver um ponteiro ao objecto.
Que operações com apontadores não têm sentido? - Apenas comparação entre si e com um número - por isso devemos negligenciá-los e colocá-los numa função especial (por exemplo, bool ComparePointer( a,b)) para preservar a possibilidade de utilização múltipla de operadores sem os quais o próprio operador se sobrecarrega perde o seu significado crucial.