I'm pretty new to C++, but I want to make sure I'm not doing something wrong here before reporting a bug to Microsoft.
Here's some sample code:
#include <system_error>
using namespace std;
class Test
{
public:
~Test()
{
throw system_error(5, system_category());
}
};
Test test;
void testfunc()
{
throw system_error(5, system_category());
}
void main()
{
try
{
testfunc();
}
catch ( const system_error& e)
{
}
}
Now, I would expect Windows to say "the runtime has requested the program to exit in an unexpected way". However, I get a "pure virtual function called" error instead. With a little debugging, I noticed that when the static class destructor gets the std::system_category
reference, the ::name
and ::message
members are pure virtual. However, when it is constructed in testfunc()
, those vtable pointers are to valid functions.
My question is, am I doing something wrong by constructing my system_error
exceptions this way? I had some code that was basically doing throw system_error(GetLastError(), system_category());
. This happened to execute in a static destructor, and I got the pure virtual function called error.
To throw exceptions from Windows' GetLastError()
function, should I be constructing my exceptions a different way, or is this a bug in msvc11's C++ runtime?
EDIT
There's been a bit of confusion about my question. My actual code is more complicated than this example, and I actually didn't expect that one of my destructors could throw. My destructor must call a function that could possibly throw. If I change my code to:
~Test()
{
try
{
callSomeFuncThatCouldThrow();
}
catch ( … ) { }
}
I will still get the pure virtual function call error. This is because when the system_error is constructed (in callSOmeFuncThatCouldThrow()
) it tries to use the ::message
member of the system_category
I'm giving it, which causes the error.
Looks like a Microsoft bug. std::error_category
is an abstract base class for various unnamed types, one of which is the type returned by system_category()
. There's one object of that type, and all calls to system_category()
return a reference to that object. What you're seeing looks like that object is being destroyed before the destructor of the test
object runs. If you want to satisfy the purists, change your destructor to:
Test::~Test() {
const std::error_category& cat = std::system_category();
std::cout << cat.name() << '\n';
}