Читаем Thinking In C++. Volume 2: Practical Programming полностью

//: C01:Nonlocal.cpp

// setjmp() & longjmp()

#include

#include

using namespace std;


class Rainbow {

public:

  Rainbow() { cout << «Rainbow()» << endl; }

  ~Rainbow() { cout << «~Rainbow()» << endl; }

};


jmp_buf kansas;


void oz() {

  Rainbow rb;

  for(int i = 0; i < 3; i++)

    cout << «there's no place like home\n»;

  longjmp(kansas, 47);

}


int main() {

  if(setjmp(kansas) == 0) {

    cout << «tornado, witch, munchkins...\n»;

    oz();

  } else {

    cout << «Auntie Em! "

         << "I had the strangest dream..."

         << endl;

  }

} ///:~


The setjmp( ) function is odd because if you call it directly, it stores all the relevant information about the current processor state (such as the contents of the instruction pointer and runtime stack pointer) in the jmp_buf and returns zero. In this case it behaves like an ordinary function. However, if you call longjmp( ) using the same jmp_buf, it’s as if you’re returning from setjmp( ) again—you pop right out the back end of the setjmp( ). This time, the value returned is the second argument to longjmp( ), so you can detect that you’re actually coming back from a longjmp( ). You can imagine that with many different jmp_bufs, you could pop around to many different places in the program. The difference between a local goto (with a label) and this nonlocal goto is that you can return to any pre-determined location higher up in the runtime stack with setjmp( )/longjmp( ) (wherever you’ve placed a call to setjmp( )).

The problem in C++ is that longjmp( ) doesn’t respect objects; in particular it doesn’t call destructors when it jumps out of a scope.[1] Destructor calls are essential, so this approach won’t work with C++. In fact, the C++ standard states that branching into a scope with goto (effectively bypassing constructor calls), or branching out of a scope with longjmp( ) where an object on the stack has a destructor, constitutes undefined behavior.

Throwing an exception

If you encounter an exceptional situation in your code—that is, one in which you don’t have enough information in the current context to decide what to do—you can send information about the error into a larger context by creating an object that contains that information and "throwing" it out of your current context. This is called throwing an exception. Here’s what it looks like:.

//: C01:MyError.cpp

class MyError {

   const char* const data;

public:

   MyError(const char* const msg = 0) : data (msg) {}

};


void f() {

   // Here we "throw" an exception object:

   throw MyError("something bad happened");

}


int main() {

   // As you’ll see shortly,

   // we’ll want a "try block" here:

   f();

} ///:~


MyError is an ordinary class, which in this case takes a char* as a constructor argument. You can use any type when you throw (including built-in types), but usually you’ll create special classes for throwing exceptions.

The keyword throw causes a number of relatively magical things to happen. First, it creates a copy of the object you’re throwing and, in effect, "returns" it from the function containing the throw expression, even though that object type isn’t normally what the function is designed to return. A naive way to think about exception handling is as an alternate return mechanism (although you find you can get into trouble if you take the analogy too far). You can also exit from ordinary scopes by throwing an exception. In any case, a value is returned, and the function or scope exits.

Any similarity to function returns ends there because where you return is some place completely different from where a normal function call returns. (You end up in an appropriate part of the code—called an exception handler—that might be far removed from where the exception was thrown.) In addition, any local objects created by the time the exception occurs are destroyed. This automatic cleanup of local objects is often called "stack unwinding.".

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT