Error del compilador con el parámetro de la plantilla = void* - página 6

 
Alexey Navoykov:

Todo funciona bien, ¿por qué te lo inventas?

En el registro obtenemos:

void A::~A()
void B::~B()

¿Por qué me lo creí...?

Pues lo siento, no sabía que se podía hacer eso, MKL no es mucho C++. En el lado positivo, la eliminación de void* es UB.

 

Foro sobre trading, sistemas de trading automatizados y pruebas de estrategias de trading

Nueva versión de MetaTrader 5 build 1930: Ventana de gráfico flotante y biblioteca .Net en MQL5

Alexey Navoykov, 2018.12.15 02:44

Estimados desarrolladores. Anteriormente, en uno de los hilos, discutimos el defecto del compilador que permite el casting implícito de una clase base a una clase derivada, pero parece haber pasado desapercibido para ti. Este es un problema grave, que dificulta la comprobación de errores y se convierte en un dolor de cabeza constante cuando se utiliza activamente la POO. Dicho casting debe ser sólo explícito. Esta es una regla general tanto para C++ como para C#.

class A {  };

class B : public A { };

A* a = new A;

B* b = a;  // Нет ошибки компиляции!

void f(B*) {  }

void OnInit()
{ 
  f(a);  // Нет ошибки компиляции!
}  

¿Y qué hacer aquí?

class A {  };

class B : public A { };

A* a = new A;

void* v = a;

B* b = v;  // Нет ошибки компиляции!


¿Debe considerarse este comportamiento como un error también?

 
Alexey Navoykov:

Si el estilizador hace que el código sea difícil de leer, ¿para qué usarlo?

Para mí, un estilista es bueno sólo cuando TODAS sus reglas pueden ser personalizadas con flexibilidad.

Por lo tanto, si lees el código de otra persona en un formulario impreso (o en un foro, como aquí).

 
fxsaber:
Sobre los paréntesis
((A*)(b.GetPtr())).f(); // Доп. скобки, чтобы подчеркнуть, что именно имелось в виду, не полагаясь на приоритеты.

Puede que a ti te destaque, pero a mí sólo me confunde. Pero viendo esta expresión, no puedo entender inmediatamente a qué método se está llamando aquí. Pero en las dos líneas anteriores, queda claro enseguida.

Para entender lo que se está haciendo hay que abrir todos los paréntesis. Cuantos más paréntesis haya, más tiempo se pierde en averiguar lo que está pasando, especialmente si no están separados por espacios.

 
Alexey Navoykov:

Puede que a ti te destaque, pero a mí sólo me confunde. Pero viendo esta expresión, no puedo entender inmediatamente a qué método se llama aquí, pero en las dos líneas anteriores, todo queda claro de inmediato.

Para entender exactamente lo que se está haciendo, hay que abrir todos los paréntesis. Cuantos más paréntesis, más tiempo se pierde en entender lo que está pasando. Especialmente si no están separados por espacios de ninguna manera.

Los paréntesis adicionales no son para leer - deja que el estilista se encargue de eso, poniendo espacios.

Pero para el autocontrol al escribir. ¿Por qué debo confiar en las prioridades de alguien cuando escribo en un área sensible, siendo consciente de que estoy escribiendo código multiplataforma (y no necesariamente sólo MT4/5) que puede ser portado a otros lenguajes? Los paréntesis adicionales eliminan por completo la influencia de las prioridades lingüísticas. Todo se vuelve absolutamente inequívoco. Por ello, hay una fiabilidad del 100% de que nada fallará en este lugar después de la siguiente construcción.


Además, cuando lea este infierno de paréntesis, tendré que dedicar tiempo a la comprensión absoluta de lo que quiero decir aquí. Y sobre el tema de la visibilidad.

bool a = (1 < 2) && (3 < 4);
bool b = 1 < 2 && 3 < 4;

preguntemos, ¿qué opción es más visual?

 
fxsaber:

¿Este comportamiento también cuenta como un error?

Por supuesto que sí. Esto es lo mismo.

Así que resulta que no se genera nada cuando realmente es posible un problema y al menos se exigen advertencias (o incluso un error de compilación). Pero no escatiman en advertencias cuando nos obligan a usar paréntesis ) Y algunos aquí incluso proponen prohibir la compilación sin paréntesis y amenazan con abofetear ) Así vivimos...

 
Alexey Navoykov:

Por supuesto. Esto es lo mismo.

Así que resulta que si hay un problema real y se requiere al menos una advertencia (o incluso un error de compilación), no se muestra nada. Pero con los corchetes no se ahorran ninguna advertencia ) Y algunos aquí incluso proponen prohibir la compilación sin corchetes y amenazan con darte un tortazo ) Así vivimos...

¿Así que tú también necesitas una advertencia? ¿Qué clase de doble rasero es ese: en ambos sitios el comportamiento es inequívoco, pero con los paréntesis estás en contra de las advertencias, y aquí estás a favor?

Necesitas una advertencia para no cometer errores difíciles de encontrar. Así que la dificultad es una evaluación subjetiva. Así que con los corchetes no te equivocas, y aquí sí. Y para mí es viceversa.

Entonces, ¿a cuál de los dos hay que ajustar las normas de emisión de avisos?

 
Ilya Malev:

No conocía el StringConcatenate, es una pena que en MT5 se haya rediseñado y no se pueda utilizar sin string s. Y el StringFormat es mucho más rápido en 4

Y en general por alguna razón esta operación de "sondeo" de un puntero a través de una cadena es casi dos veces más lenta en 5, aunque en general funciona más rápido allí, a veces por un orden

es posible que StringConcatenate() sea de 32 bits, no se sabe, los desarrolladores ya han escrito que los metaetiters en la 5 y en la 4 son los mismos, quizás por compatibilidad lo "envolvieron"

Ayer intenté resolver tu problema, el problema es que MQL no permite hacer referencia a los punteros. la función en un método de la clase puede ser llamado a través de dynamic_cast<C_myclass >( func( ) ), puede obtener un puntero a la clase a través de dynamic_cast< > pero ¿qué hacer con un puntero? - puedes reasignar void *ptr , pero no tiene sentido porque el puntero no puede ser dereferenciado de todas formas

 
pavlick_:

Si quieres desechar CArayObject, tienes que hacer un override (como este https://www.mql5.com/ru/forum/170952/page110#comment_9894796) sobre la clase base y ponerlos en un array (posiblemente el tuyo), pero entonces ya no necesitarás void*.

No estoy en contra del vacío*, es necesario, pero en una capacidad diferente.

No veo el sentido del código por referencia (aunque tampoco uso bibliotecas estándar). Si poner un objeto en un array implica crear una copia del mismo, entonces el método de asignación o el constructor de la copia deben ser declarados y descritos explícitamente en esa clase, de lo contrario ninguna envoltura servirá de todos modos. Si sólo necesitas poner una referencia a un objeto en un array, no necesitas ninguna envoltura (¿por qué?).

Por cierto, parece que no sabes que if(p) delete p no es idéntico a "si la referencia apunta a un objeto dinámico existente, elimínalo" en mql.

class A{};

void OnStart()
 {
  A *a=new A;
  if(a) Print("Кукареку!");
  if(CheckPointer(a)==POINTER_DYNAMIC) Print("Динамический объект существует и может быть удален");
  else                                 Print("Объект не существует, либо он автоматический");
  delete a;
  if(a) Print("Кукареку!");
  if(CheckPointer(a)==POINTER_DYNAMIC) Print("Динамический объект существует и может быть удален");
  else                                 Print("Объект не существует, либо он автоматический");
 }
 
fxsaber:

Y sobre el tema de la visibilidad.

preguntemos, ¿cuál es más claro?

Bueno, si es así como el estilista lo formateó para ti :

1 < 2 && 3 < 4;

entonces, de nuevo, depende del estilista. Nunca haría esto en mi código. Lo haría de esta manera:

1<2 && 3<4
либо
1 < 2  &&  3 < 4