Bug del compilatore con il parametro template = void* - pagina 6

 
Alexey Navoykov:

Tutto funziona bene, perché ti stai inventando tutto?

Nel registro otteniamo:

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

Perché ci sono cascato...

Beh, allora mi dispiace, non sapevo che si potesse fare, MKL è molto diverso da C++. Il lato positivo è che la rimozione di void* è UB.

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Nuova versione di MetaTrader 5 build 1930: Finestra del grafico fluttuante e libreria .Net in MQL5

Alexey Navoykov, 2018.12.15 02:44

Cari sviluppatori. Prima in uno dei thread abbiamo discusso il difetto del compilatore che permette il casting implicito di una classe base su una classe derivata, ma sembra essere rimasto inosservato da voi. Questo è un problema serio, che rende difficile il controllo degli errori e diventa un mal di testa costante quando si usa attivamente OOP. Tale casting dovrebbe essere solo esplicito. Questa è una regola generale sia per C++ che C#.

class A {  };

class B : public A { };

A* a = new A;

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

void f(B*) {  }

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

E cosa fare qui?

class A {  };

class B : public A { };

A* a = new A;

void* v = a;

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


Anche questo comportamento dovrebbe essere considerato un errore?

 
Alexey Navoykov:

Se lo styler rende il codice difficile da leggere, allora perché diavolo usarlo?

Per me, uno styler è buono solo quando TUTTE le sue regole possono essere personalizzate in modo flessibile.

Quindi, se leggete il codice di qualcun altro in forma stampata (o su un forum, come qui).

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

Beh, forse vi enfatizzerà, ma per me confonderà soltanto. Ma guardando questa espressione, non riesco a capire immediatamente di chi sia il metodo che viene chiamato qui. Ma nelle due righe precedenti, è subito chiaro.

Per capire cosa si sta facendo si dovrebbero aprire tutte le parentesi. Più parentesi ci sono, più tempo si perde per capire cosa sta succedendo, specialmente se non sono separate da spazi.

 
Alexey Navoykov:

Beh, forse vi enfatizzerà, ma per me confonderà soltanto. Ma guardando questa espressione, non riesco a capire immediatamente di chi sia il metodo chiamato qui. Ma nelle due righe precedenti, tutto è chiaro subito.

Per capire esattamente cosa si sta facendo, bisogna aprire tutte le parentesi. Più parentesi - più tempo si spende per capire cosa sta succedendo. Specialmente se non sono separate da spazi in alcun modo.

Le parentesi aggiuntive non servono per la lettura - lascia che se ne occupi lo styler, mettendo degli spazi.

Ma per l'autocontrollo durante la scrittura. Perché dovrei fare affidamento sulle priorità di qualcuno quando scrivo in un'area sensibile, pur essendo consapevole che sto scrivendo codice multipiattaforma (e non necessariamente solo MT4/5) che può essere portato in altre lingue? Le parentesi aggiuntive eliminano completamente l'influenza delle priorità linguistiche. Tutto diventa assolutamente non ambiguo. Per questo motivo c'è un'affidabilità del 100% che nulla si guasterà in questo posto dopo la prossima costruzione.


Inoltre, quando leggerò questo inferno di staffe, dovrò dedicare del tempo alla comprensione assoluta di ciò che intendo qui. E a proposito di visibilità.

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

chiediamoci, quale opzione è più visiva?

 
fxsaber:

Anche questo comportamento conta come un errore?

Certo che lo fa. Questa è la stessa cosa.

Così si scopre che non viene generato nulla laddove un problema è davvero possibile e si richiede almeno un avvertimento (o anche un errore di compilazione). Ma non risparmiano alcun avvertimento quando le parentesi ci vengono imposte ) E alcune persone qui propongono addirittura di vietare la compilazione senza parentesi e minacciano di prenderci a schiaffi ) Così si vive...

 
Alexey Navoykov:

Naturalmente. Questa è la stessa cosa.

Così si scopre che se c'è un problema reale ed è necessario almeno un avvertimento (o anche un errore di compilazione), non viene mostrato nulla. Ma con le parentesi non risparmiano alcun avvertimento ) E alcune persone qui propongono addirittura di vietare la compilazione senza parentesi e minacciano di prenderti a schiaffi ) Così si vive...

Quindi anche tu hai bisogno di un avvertimento? Che razza di doppio standard è questo: in entrambi i posti il comportamento è inequivocabile, ma con le parentesi siete contro gli avvertimenti, e qui siete a favore?

Hai bisogno di un avvertimento per non fare errori difficili da trovare. Quindi la difficoltà è una valutazione soggettiva. Quindi con le parentesi non si fanno errori, e qui è possibile. E per me è il contrario.

Quindi a chi di noi dovrebbero essere adattate le regole per l'emissione di avvertimenti?

 
Ilya Malev:

Non sapevo di StringConcatenate, è un peccato che in MT5 sia stato ridisegnato e non possa essere usato senza stringa s. E lo StringFormat è molto più veloce su 4

E in generale per qualche motivo questa operazione di "polling" di un puntatore attraverso una stringa è quasi due volte più lenta in 5, anche se in generale funziona più velocemente, a volte di un ordine

è possibile che StringConcatenate() sia a 32 bit, non si sa, gli sviluppatori hanno già scritto che i metaetiter in 5 e 4 sono gli stessi, forse per compatibilità lo hanno "avvolto"

Ieri ho provato a risolvere il tuo problema con dynamic_cast< >. Il problema è che MQL non permette di dereferenziare i puntatori. la funzione in un metodo di classe può essere chiamata tramite dynamic_cast<C_myclass >( func( ) ), è possibile ottenere un puntatore alla classe tramite dynamic_cast< > ma cosa fare con un puntatore? - potete riassegnare void *ptr , ma non ha senso perché il puntatore non può essere comunque dereferenziato

 
pavlick_:

Se volete eliminare CArayObject, dovete fare un override (come questo https://www.mql5.com/ru/forum/170952/page110#comment_9894796) sulla classe base e metterli in un array (possibilmente vostro), ma poi non avrete più bisogno di void*.

Non sono contro il vuoto*, è necessario, ma in una veste diversa.

Non vedo il senso del codice per riferimento (anche se non uso nemmeno le librerie standard). Se mettere un oggetto in un array implica la creazione di una copia di esso, allora il metodo di assegnazione o il costruttore di copia devono essere dichiarati e descritti esplicitamente in quella classe, altrimenti nessun wrapper aiuterà comunque. Se avete solo bisogno di mettere un riferimento a un oggetto in un array, non avete bisogno di nessun wrapper (perché?).

A proposito, sembra che tu non sappia che if(p) delete p non è identico a "se il riferimento punta a un oggetto dinamico esistente, cancellalo" in 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:

E a proposito di visibilità.

chiediamoci, quale è più chiaro?

Beh, se è così che lo styler lo ha formattato per te :

1 < 2 && 3 < 4;

poi, di nuovo, dipende dallo stilista. Non lo farei mai nel mio codice, ma in questo modo:

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