Errori, bug, domande - pagina 2198

 
fxsaber:

Nessuna differenza


Quando si scrive, sembra dipendere dai numeri che si digitano. Alcuni di essi non ti permettono di digitare. E alcuni di loro lo fanno.

Strano comportamento... Se si digita un numero intero inferiore a 12 cifre, potrebbe saltare un totale di più di 14.

Aspetteremo di vedere cosa dicono gli sviluppatori.

 
Per favore aiutatemi a fare una cosa semplice
class A
{
public:  
  int i;
  
  A* operator *( const A &Value ) const
  {
    A* Res = new A;
    
    Res.i = this.i * Value.i;
    
    return(Res);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
  
  delete d;
}

Potete vedere chiaramente nel codice che ci dovrebbe essere una perdita di memoria. Ed è esattamente quello che sta succedendo. Tuttavia, come scriverlo correttamente per poter "moltiplicare" gli oggetti? Tutto è chiaro con l'operatore "*=", come è chiaro nel caso delle strutture. Ma con le classi, come implementare questa semplice funzionalità?


SZZ E questo codice.

class A
{
private:
  A Tmp;
  
public:
  int i;
  
  A* operator *( const A &Value )
  {
    this.Tmp.i = this.i * Value.i;
    
    return(&Tmp);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
}

Blocca ME con F7 e uccide il terminale con F5. Perché sono così fortunato!

 
fxsaber:

ZS E questo codice

Arresta ME su F7 e uccide il terminale su F5. Perché sono così fortunato?

class A
{
private:
  A Tmp;
  
public:
  int i;
  
  A* operator *( const A &Value )
  {
    this.Tmp.i = this.i * Value.i;
    
    return(&Tmp);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
}

Probabilmente ricorsione infinita e stack overflow.

 
Sergey Dzyublik:

Possibile ricorsione infinita e stack overflow.

Certamente il problema è in quello assegnato, ma la causa sembra essere più profonda.

E ovviamente non ci dovrebbe essere alcuna ricorsione a runtime.

 
fxsaber:
Per favore, aiutatemi a fare una cosa semplice
class A
{
public:
  A() {}
  A(const A& other) 
  {
   this.i = other.i;
  }
  
  int i;
  
  A operator *( const A &Value ) const
  {
    A Res;
    
    Res.i = this.i * Value.i;
    
    return(Res);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A d = a * b * c;
  
  Print(d.i); // 30
}
Le spese generali, naturalmente, ma se la convenienza è più importante...
 
Комбинатор:
Le spese generali naturalmente lo saranno, ma se la convenienza è più importante...

Grazie! Si scopre che oggetto di ritorno e "=" quando si definisce un oggetto passano attraverso un costruttore aggiuntivo.

In realtà mi piacerebbe vedere una tabella chiara da qualche parte, quali casi si chiamano costruttori (e quali), e quali operatori. In questo momento tutto è intuitivo, il che non funziona, ovviamente.

 
fxsaber:

In realtà mi piacerebbe vedere una tabella da qualche parte, dove vengono chiamati i costruttori (e quali) e dove vengono chiamati gli operatori. In questo momento è tutto a livello di intuizione, e fallisce, ovviamente.

Se restituite qualcosa per valore, sarà assegnato tramite copy-constructor (se è dello stesso tipo) se è una definizione o operatore se non lo è.

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A d = a * b * c;
  // код аналогичен A d(a * b * c);
  // будет вызван копи-конструктор.

  A e;
  e = a * b * c;
  // будет вызван оператор =
  // но копи-конструктор все равно нужен для множественного умножения
  
  Print(d.i); // 30
}
 
Комбинатор:

Se restituite qualcosa per valore, sarà assegnato tramite copia-costruttore (se è dello stesso tipo) se è una definizione o operatore se non lo è.

Detto chiaramente, grazie!


SZZ ha innescato il tuo codice

class A
{
public:
  A() { Print(__FUNCSIG__); }
  A(const A& other) 
  {
   Print(__FUNCSIG__);
   this.i = other.i;
  }
  
  ~A()
  {
   Print(__FUNCSIG__);
  }
  
  int i;
  
  A operator *( const A &Value ) const
  {
    Print(__FUNCSIG__);

    A Tmp;
    
    Tmp.i = this.i * Value.i;
        
    return(Tmp);
  }
};

void OnStart()
{
  if (true)
  {
    A a, b, c;
    
    a.i = 2;
    b.i = 3;
    c.i = 5;
    
    A d = a * b * c;

    Print(d.i); // 30
  }
  
  Print("Kill!");  
}


Risultato

void A::A() // a
void A::A() // b
void A::A() // c
A A::operator*(const A&) const
void A::A() // Tmp
void A::A(const A&) // return
void A::~A() // Tmp
A A::operator*(const A&) const
void A::A() // Tmp
void A::A(const A&) // return
void A::~A() // Tmp
void A::A(const A&) // d
30
void A::~A() // a
void A::~A() // b
void A::~A() // c
void A::~A() // d
void A::~A() // return
void A::~A() // return
Kill!

Le linee evidenziate sollevano delle domande. Perché gli oggetti temporanei non sono andati in crash non appena sono stati usati? Cioè, prima dell'uscita di trenta. Tali oggetti manderebbero in crash la mia macchina, che dovrebbe gestire decine di milioni di tick. Ogni oggetto trangugia gigabyte di RAM, e non voglio avere questi oggetti temporanei invece di ucciderli immediatamente.

 
fxsaber:

Le linee evidenziate sollevano delle domande. Perché gli oggetti temporanei non sono andati in crash non appena sono stati usati? Cioè prima dell'uscita dei trenta.

Di solito gli oggetti temporanei non vengono cancellati immediatamente, ma alla fine del contesto.

Se volete una cancellazione veloce, controllate il contesto.

void OnStart()
{
  if (true)
  {
    A a, b, c;
    
    a.i = 2;
    b.i = 3;
    c.i = 5;
    
    A d;
    {
      d = a * b * c;
    }

    Print(d.i); // 30
  }
  
  Print("Kill!");  
}

Vero, dovrete usare l'operatore =

 
A100:

Sul mio nuovo grafico, l'esempio ha funzionato solo quando l'ho riavviato (tutti i pulsanti), il che di per sé è incomprensibile. Ma ora capisco questo

Con l'apertura delle transazioni, l'effetto specificato è sparito (solo al riavvio)

Apportate modifiche alla documentazione. Il problema con il codice era che l'invio di un ordine dell'evento del mouse al grafico mette solo il comando nella coda del grafico. E se questa coda non viene elaborata (per esempio nel fine settimana), il grafico non può ricevere gli eventi specificati. Una nota e un esempio corretto sono stati aggiunti nella descrizione di ChartSetInteger:

Nota

La funzione è asincrona - significa che la funzione non aspetta l'esecuzione del comando, accodato con successo per il grafico specificato, ma restituisce il controllo immediatamente. La proprietà cambierà solo dopo che il comando è stato elaborato nella coda del grafico. La funzione ChartRedraw deve essere chiamata per eseguire immediatamente i comandi nella coda del grafico.

Se hai bisogno di cambiare immediatamente diverse proprietà del grafico, le funzioni appropriate (ChartSetString, ChartSetDouble, ChartSetString) devono essere eseguite in un blocco di codice e poi ChartRedraw deve essere chiamato una volta sola.

Per controllare il risultato dell'esecuzione, puoi usare una funzione che interroga la proprietà del grafico specificata (ChartGetInteger, ChartGetDouble, ChartSetString). Notate che queste funzioni sono sincrone e aspettano il risultato dell'esecuzione.

Esempio:

//+------------------------------------------------------------------+
//| Funzione di inizializzazione dell'esperto|
//+------------------------------------------------------------------+
voidOnInit()
{
//--- abilitare i messaggi sul movimento del mouse attraverso la finestra del grafico
ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);
//--- l'aggiornamento forzato delle proprietà del grafico assicura la prontezza per la gestione degli eventi
ChartRedraw()
;
}