Frage

Ich habe zwei Funktionen:

void prepe () und void fund (), die nacheinander bezeichnet werden:

prepare();
<do something>;
finish(); 
... 
prepare(); 
<do something>; 
finish();

Ich möchte eine einfache Behauptung machen, einfach zu testen, dass sie tatsächlich so genannt werden und dass sie in der Anwendung nicht gleichzeitig oder außerordentlich bezeichnet werden.

Diese Anwendung ist eine Einzelanwendung. Dies ist eine einfache Prüfung für Entwicklungs-/Testen, um sicherzustellen, dass diese Funktionen in Ordnung bezeichnet werden und dass sie aus irgendeinem Grund nicht gleichzeitig genannt werden. Darüber hinaus sollten diese Behauptungen/Vernunftprüfungen aus dem Produktionscode weggelassen werden, da die Leistung von entscheidender Bedeutung ist!

Würde ein einfaches Assert () wie diese am besten funktionieren?

int test = 0;

void prepare() {
   assert(++test == 1);

   .
   .
   .
}

void finish() {
    assert(--test == 0);

    .
    .
    .
}
War es hilfreich?

Lösung

Ihr Code ist in Ordnung, es sei denn, Sie müssen das Verschachteln zulassen prepare und finish Anrufe.

Wenn Nesting nicht erlaubt ist, können Sie a verwenden bool statt eines int:

bool locked = false;;

void prepare() {
    assert( ! locked );
    locked = true;
    ...
}

void finish() {
    assert( locked );
    locked = false;
    ...
}

Andere Tipps

Vielleicht möchten Sie sich ändern

int test = 0;

zu

#ifndef NDEBUG
int test = 0;
#endif

Um Ihre Anforderung zu erfüllen, dass "jeder Code in Bezug auf diesen Test in der Produktion weggelassen werden sollte".

Sie wollen wahrscheinlich:

int test = 0;

void prepare() {
    // enter critical section
    assert(test++ == 0);

    .
    .
    .
    // leave critical section 
}

void finish() {
    // enter critical section
    assert(--test == 0);

    .
    .
    .
    // leave critical section
}

Hier gibt es eine Rennbedingung: zwei gleichzeitige Fälle von prepare könnte den Wert von nehmen test Gleichzeitig erhöhen beide es in einem Register, um beide zu erhalten 1, dann machen Sie den Vergleich, um zu bekommen true.

Ich mach das volatile ist Ich werde nicht helfen. Stattdessen sollten Sie einen Mutex anlegen test, wie so:

boost::mutex mtx;
int test = 0;

void prepare()
{
    boost::mutex::scoped_try_lock lock(&mtx);
    assert(lock.owns_lock());
    assert(test++ == 0);
    // ...
}

void finish()
{
    boost::mutex::scoped_try_lock lock(&mtx);
    assert(lock.owns_lock());
    assert(--test == 0);
}

Wenn Sie setzen <do something>; in ein class Sie können die Notwendigkeit eines Schecks reduzieren:

Halten Sie einfach den Konstruktoraufruf prepare und der Zerstörer -Anruf finish. Dann wird automatisch durchgesetzt, dass sie angemessen genannt werden.

Beachten Der Zähler müsste mutex geschützt werden.

Beachten Sie auch, dass Sie auch privat machen können operator new/delete um zu verhindern, dass jemand einen auf dem Haufen schafft und ihn nicht zerstört.

Wenn Sie C ++ verwenden, verwenden Sie Raii nicht? Sie müssten immer noch nach Wiedereintritt suchen, aber Raii vereinfacht die Dinge erheblich. Kombiniert mit Larsmans 'Mutex und Raedwalds Eliminierung in Ndebug:

struct Frobber {
  Frobber() {
    assert(mtx.try_lock());
#ifndef NDEBUG
    try {  // in case prepare throws
#endif
      prepare();
#ifndef NDEBUG
    }
    catch (...) {
      mtx.unlock();
      throw;
    }
#endif
  }

  void something();
  // And the other actions that can be performed between preparation and finishing.

  ~Frobber() {
    finish();
#ifndef NDEBUG
    mtx.unlock();
#endif
  }

private:
#ifndef NDEBUG
  static boost::mutex mtx;
#endif

  Frobber(Frobber const&);  // not defined; 0x: = delete
  Frobber& operator=(Frobber const&);  // not defined; 0x: = delete
};
#ifndef NDEBUG
boost::mutex Frobber::mtx;
#endif

void example() {
  Frobber blah;  // instead of prepare()
  blah.something();
  // implicit finish()
}

Im Beispiel im Beispiel Sie einfach kann nicht Tun Sie etwas, ohne sich zuerst vorzubereiten, und das Ende wird immer passieren, auch wenn eine Ausnahme ausgelöst wird.

Randnotiz zu NDEBUG: Wenn Sie es so verwenden, stellen Sie sicher, dass es entweder immer definiert oder immer unbestimmt ist alle Übersetzungseinheiten, im Gegensatz zu der Art und Weise, wie sie für die Behauptung verwendet werden (so dass sie an verschiedenen Stellen definiert und nicht definiert werden können).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top