Fehler, Irrtümer, Fragen - Seite 2198

 
fxsaber:

Kein Unterschied


Bei der Eingabe scheint es von den Zahlen abzuhängen, die Sie eingeben. Bei einigen ist es nicht möglich, zu tippen. Und einige von ihnen tun es.

Seltsames Verhalten... Wenn Sie eine ganze Zahl mit weniger als 12 Ziffern eingeben, werden möglicherweise mehr als 14 Stellen übersprungen.

Wir werden abwarten, was die Entwickler sagen.

 
Bitte helfen Sie mir, eine einfache Sache zu tun
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;
}

Im Code ist deutlich zu erkennen, dass es ein Speicherleck geben sollte. Und genau das ist der Fall. Aber wie schreibt man es richtig, um Objekte "multiplizieren" zu können? Mit dem Operator "*=" ist alles klar, ebenso wie bei den Strukturen. Aber wie lässt sich diese einfache Funktionalität mit Klassen umsetzen?


SZZ Und dieser Code.

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
}

Bringt ME mit F7 zum Absturz und beendet das Terminal mit F5. Was habe ich für ein Glück!

 
fxsaber:

ZS Und dieser Code

Bringt ME auf F7 zum Absturz und tötet Terminal auf F5. Warum habe ich so viel Glück?!

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
}

Wahrscheinlich unendliche Rekursion und Stapelüberlauf.

 
Sergey Dzyublik:

Möglicherweise unendliche Rekursion und Stapelüberlauf.

Sicherlich liegt das Problem in der zugewiesenen, aber die Ursache scheint tiefer zu liegen.

Und natürlich sollte es keine Rekursion zur Laufzeit geben.

 
fxsaber:
Bitte helfen Sie mir, eine einfache Sache zu tun
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
}
Gemeinkosten natürlich, aber wenn Bequemlichkeit wichtiger ist...
 
Комбинатор:
Gemeinkosten werden natürlich anfallen, aber wenn Bequemlichkeit wichtiger ist...

Ich danke Ihnen! Es stellt sich heraus, dass return object und "=" bei der Definition eines Objekts durch einen zusätzlichen Konstruktor gehen.

Ich würde gerne irgendwo eine klare Tabelle sehen, welche Fälle als Konstruktoren (und welche als Operatoren) bezeichnet werden. Im Moment ist alles intuitiv, was natürlich nicht funktioniert.

 
fxsaber:

Ich würde eigentlich gerne irgendwo eine Tabelle sehen, wo Konstruktoren aufgerufen werden (und welche) und wo Operatoren aufgerufen werden. Im Moment läuft alles auf der Ebene der Intuition ab, und die versagt natürlich.

Wenn Sie etwas als Wert zurückgeben, wird es über den Copy-Constructor zugewiesen (wenn es vom gleichen Typ ist), wenn es eine Definition ist, oder über den Operator, wenn nicht.

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
}
 
Комбинатор:

Wenn Sie etwas als Wert zurückgeben, wird es über den Kopier-Konstruktor zugewiesen (wenn es vom gleichen Typ ist), wenn es eine Definition ist, oder über den Operator, wenn nicht.

Klar und deutlich gesagt, danke!


SZZ hat Ihren Code vorbereitet

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!");  
}


Ergebnis

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!

Die hervorgehobenen Zeilen werfen Fragen auf. Warum stürzten die temporären Objekte nicht ab, sobald sie verwendet wurden? Das heißt, vor der Ausgabe von dreißig. Solche Objekte würden meinen Rechner zum Absturz bringen, da er mehrere zehn Millionen Ticks verarbeiten soll. Jedes Objekt wird Gigabytes an Arbeitsspeicher verschlingen, und ich möchte solche temporären Objekte nicht haben, anstatt sie sofort zu löschen.

 
fxsaber:

Die hervorgehobenen Zeilen werfen Fragen auf. Warum stürzten die temporären Objekte nicht ab, sobald sie verwendet wurden? D.h. vor der Ausgabe von dreißig.

Normalerweise werden temporäre Objekte nicht sofort gelöscht, sondern erst am Ende des Kontexts.

Wenn Sie eine schnelle Löschung wünschen, kontrollieren Sie den Kontext.

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!");  
}

Richtig, Sie müssen den Operator = verwenden

 
A100:

Bei meinem neuen Diagramm funktionierte das Beispiel nur, wenn ich es neu startete (alle Schaltflächen), was an sich unverständlich ist. Aber jetzt verstehe ich das

Bei der Eröffnung von Geschäften ist der angegebene Effekt weg (nur bei Neustart)

Änderungen an der Dokumentation vorgenommen. Das Problem mit dem Code war, dass das Senden eines Mausereignisbefehls an das Diagramm nur den Befehl in die Warteschlange des Diagramms stellt. Und wenn diese Warteschlange nicht abgearbeitet wird (z. B. am Wochenende), kann das Diagramm die angegebenen Ereignisse nicht empfangen. Hinweis und korrigiertes Beispiel zur ChartSetInteger-Beschreibung hinzugefügt:

Hinweis

Die Funktion ist asynchron - das bedeutet, dass die Funktion nicht auf die Ausführung des Befehls wartet, der erfolgreich in der Warteschlange für das angegebene Diagramm steht, sondern die Kontrolle sofort zurückgibt. Die Eigenschaft ändert sich erst, nachdem der Befehl in der Grafikwarteschlange verarbeitet wurde. Die Funktion ChartRedraw muss aufgerufen werden, um Befehle in der Diagrammwarteschlange sofort auszuführen.

Wenn Sie mehrere Diagrammeigenschaften sofort ändern müssen, müssen die entsprechenden Funktionen (ChartSetString, ChartSetDouble, ChartSetString) in einem Codeblock ausgeführt und anschließend ChartRedraw einmal aufgerufen werden.

Um das Ergebnis der Ausführung zu überprüfen, können Sie eine Funktion verwenden, die die angegebene Diagrammeigenschaft abfragt (ChartGetInteger, ChartGetDouble, ChartSetString). Beachten Sie, dass diese Funktionen synchron sind und auf das Ergebnis der Ausführung warten.

Beispiel:

//+------------------------------------------------------------------+
//| Experten-Initialisierungsfunktion|
//+------------------------------------------------------------------+
voidOnInit()
{
//--- Meldungen über die Mausbewegung durch das Diagrammfenster aktivieren
ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);
//--- Die erzwungene Aktualisierung der Diagrammeigenschaften gewährleistet die Bereitschaft zur Ereignisbehandlung
ChartRedraw()
;
}