When you throw ex it is copied in a special memory location used for thrown exception objects. Such copy is carried out by the normal copy constructor.
You can see this easily from this example:
#include <iostream>
void ThrowIt();
class TestException
{
public:
TestException()
{
std::cerr<<this<<" - inside default constructor"<<std::endl;
}
TestException(const TestException & Right)
{
(void)Right;
std::cerr<<this<<" - inside copy constructor"<<std::endl;
}
~TestException()
{
std::cerr<<this<<" - inside destructor"<<std::endl;
}
};
int main()
{
try
{
ThrowIt();
}
catch(TestException & ex)
{
std::cout<<"Caught exception ("<<&ex<<")"<<std::endl;
}
return 0;
}
void ThrowIt()
{
TestException ex;
throw ex;
}
Sample output:
matteo@teolapubuntu:~/cpp/test$ g++ -O3 -Wall -Wextra -ansi -pedantic ExceptionStack.cpp -o ExceptionStack.x
matteo@teolapubuntu:~/cpp/test$ ./ExceptionStack.x
0xbf8e202f - inside default constructor
0x9ec0068 - inside copy constructor
0xbf8e202f - inside destructor
Caught exception (0x9ec0068)
0x9ec0068 - inside destructor
By the way, you can see here that the memory location used for the thrown object (0x09ec0068) is definitely far away from the one of the original object (0xbf8e202f): the stack, as usual, has high addresses, while the memory used for the thrown object is quite down in the virtual address space. Still, this is an implementation detail, since, as other answers pointed out, the standard do not say anything about where the memory for thrown object should be and how should it be allocated.