1) The storage of the exception object can be anywhere. Technically, doing "throw x;" where x is some object or value, then x ceases to exist when control passes out of the scope in which it was created. For example;
Code:
void f()
{
{
SomeType x;
throw x;
}
// x does not exist here
}
While x ceases to exist as soon as control is returned to an enclosing scope, a
temporary copy of x exists until the exception is caught (or the program terminates due to an uncaught exception) -- and will be copied repeatedly as control passes to enclosing scopes. Then compiler implementation details kick in, as the standard explicitly allows (as opposed to "requires") the compiler to avoid creating a temporary if the only way of detecting that temporary is by tracking constructor and destructor calls.
2) and 3) The reference e exists until control leaves the scope of the catch block, as does the object e refers to. If the catch block rethrows the exception then, logically, a copy of the exception object will be created, and copied during stack unwinding. Practically, again, the compiler is allowed to be smarter than that, so it can avoid creating copies.