So in the reference manual, the what() method is described as virtual, but it doesn't seem to be acting that way. (I am compiling with g++ and the c++11 flag)
#include <stdio.h> //printf
#include <iostream> //cout
#include <stdexcept>// std::invalid_argument
using namespace std;
void fn(){
throw runtime_error("wowwowo");
}
int main(){
try {fn(); }
catch(exception a) {cout << a.what() << endl;}
return 0;
}
The output for this is "std::exception", as opposed to the error message, "wowwowo". However, if I change the catch type to runtime_error, it behaves as expected. I have some code where I would like to catch exceptions that may or may not be runtime_errors, and I suppose I could have multiple catch blocks, but I'm curious as to why the code behaves as it does. Here's the code that prints out the error message:
#include <stdio.h> //printf
#include <iostream> //cout
#include <stdexcept>// std::invalid_argument
using namespace std;
void fn(){
throw runtime_error("wowwowo");
}
int main(){
try {fn(); }
catch(runtime_error a) {cout << a.what() << endl;}
return 0;
}
Change this statement:
catch(exception a) {cout << a.what() << endl;}
to this:
catch(const exception &a) {cout << a.what() << endl;}
You have to catch an exception by reference in order for it to use polymorphism. Otherwise, you are slicing the std::runtime_error object so only a std::exception object remains, thus std::exception::what() will be called instead of std::runtime_error::what().
As for the function itself, it is indeed a virtual function.
class exception {
public:
//...
virtual const char* what() const noexcept;
};
Related
#include <iostream>
#include <sstream>
using std::string;
using std::cout;
using std::endl;
using std::ostringstream;
class illegalParameterValue {
private:
string message;
public:
illegalParameterValue() : message("Illegal parameter value") {}
explicit illegalParameterValue(const char* theMessage) {message = theMessage;}
void outputMessage() {cout << message << endl;}
};
int main() {
ostringstream s;
s << "index = " << 1 << " size = " << 2;
throw illegalParameterValue(s.str().c_str());
return 0;
}
I just use some code like this, but the throw will remind some warnings which called
Clang-Tidy: Throwing an exception whose type 'illegalParameterValue' is not derived from 'std::exception'
How can I solve this problem?
consider the following code:
try {
// do something that might throw an exception
}
catch (const std::exception &ex) {
// handle the exception
}
If you derive your illegalParameterValue class from std::exception, then the catch clause above will catch it (along with other kinds of exceptions derived from std::exception). As currently written, it will not. Your users will have to add another catch clause:
try {
// do something that might throw an exception
}
catch (const std::exception &ex) {
// handle std exceptions
}
catch (const illegalParameterValue &ip) {
// handle illegal parameter exeception
}
Maybe that's what you want, maybe not.
But there's a lot of code out there like the first case.
How to build a custom string inside what() function of exception class and return it? The following code does not work but presents what I want to achieve:
class divide_by_zero : public exception {
public:
divide_by_zero(int a) : a(a) {}
const char * what() noexcept {
stringstream ss;
ss << "Division " << a << " by zero!";
return ss.str().c_str();
}
private:
int a;
};
How to build a custom string inside what() function of exception class and return it?
Don't do that. It won't work.
Instead, build the custom string inside the constructor, store the string in a member, and return a pointer to the data owned by the member in what.
Technically, you can delay building the string until the first call to what. The primarily important thing is to store the string in a member rather than a local variable, and to not invalidate the returned pointer. Such delay is unnecessary complexity however, it is simpler to build the string in the constructor.
Your local stringstream is being destroyed too early as it's only local.
Cache the message result with the exception object.
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
using std::cout;
using std::exception;
using std::stringstream;
using std::string;
class divide_by_zero : public exception {
public:
divide_by_zero(int aa) : a{aa} {}
const char * what() const noexcept override {
if (msg.empty()) {
stringstream ss;
ss << "Division " << a << " by zero!";
msg = ss.str();
}
return msg.c_str();
}
private:
int a;
mutable string msg;
};
int main() {
try {
throw divide_by_zero(75);
} catch(exception const& ex) {
cout << "Caught exception " << ex.what() << "\n";
}
}
UPDATE, or use eerorika's recommendation:
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
using std::cout;
using std::exception;
using std::stringstream;
using std::string;
class divide_by_zero : public exception {
public:
divide_by_zero(int a) : msg{make_msg(a)} {}
char const* what() const noexcept override {
return msg.c_str();
}
private:
string msg;
static string make_msg(int a) {
stringstream ss;
ss << "Division " << a << " by zero!";
return ss.str();
}
};
int main() {
try {
throw divide_by_zero(75);
} catch(exception const& ex) {
cout << "Caught exception " << ex.what() << "\n";
}
}
You can format and store that string in the constructor and return it later on:
#include <cstdio>
#include <exception>
class divide_by_zero : public std::exception {
public:
divide_by_zero(int const a) {
std::sprintf(buff, formatStr, a);
}
const char * what() const noexcept override {
return buff;
}
private:
static constexpr auto& formatStr = "Division %d by zero!";
char buff[sizeof(formatStr) + 20];
};
This does no dynamic allocation, which is better in the case of exception handling.
I'm trying to create a class with a method to handle all exceptions. It accepts a pointer to a function, executes that function and then will handle if the function throws an exception. I then created a function get an invalid substring to prove the exception is caught, however, my class isn't getting the exception and Visual Studio is breaking on the substring line saying "Exception Unhandled"
cpp file:
#include "TestHarness.h"
using namespace TestHarness;
int testFunc();
int main()
{
Tester myTest;
std::cout << myTest.execute(testFunc);
return 0;
}
int testFunc()
{
std::cout << "My Test Func" << std::endl << std::endl;
std::string("abc").substr(10);
return 6;
}
h file:
#define TESTHARNESS_H
#include <vector>
#include <iostream>
#include <sstream>
#include <string>
namespace TestHarness
{
class Tester
{
public:
int execute(int(*func)());
private:
bool result;
};
int Tester::execute(int(*func)())
{
try {
(*func)();
result = true;
return 1;
}
catch (const std::runtime_error& e)
{
std::cout << e.what();
result = false;
return 0;
}
}
}
#endif
It's simple, really: substr throws std::out_of_range, which does not derive from std::runtime_error but from std::logic_error, itself derived from std::exception. Just catch std::exception const & or std::logic_error const &. Here is a list of inheritance for all standard exception types.
The following code makes it so that a destructor is called twice.
#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib>
void myterminate()
{
std::cout << "terminate\n";
abort();
}
class data
{
int a;
public:
data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
~data() { std::cout << "dtor " << a << "\n"; }
static data failure(int a) { return data(a); }
};
void main()
{
std::set_terminate(myterminate); //terminate is not called
try
{
std::unique_ptr<data> u;
u.reset(&data::failure(1));
std::cout << "no worries\n"; //this prints
//destructor called at try-block end and attempt to destruct an invalid memory block.
}
catch (...)
{
std::cout << "caught\n"; //this can not catch the error
}
std::cout << "end\n"; //program crash, will not be called
}
How would I catch an error like this in production?
On a Release build the program crashes. On a Debug build it the on my system is:
How would I catch an error like this in production?
You cannot. The standard says that invalid memory access has undefined behaviour. There is no standard way to "catch" UB. Catching and terminate handler are for exceptions, which are defined behaviour.
What you could do, is use the debug build in production, and run it with valgrind or similar tool, so that you can at least analyze the error.
"try/catch" such mistakes will not catch, because in this case a great probability of a crash. But a moment of destruction you can try to catch, using signals and more menne dignified exit the program.
Looking away: #include , signal(), sig_atomic_t ...
First as noted in the comments you declare main as void main where the standard only allows two forms in § 3.6.1
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a declared return type of type
int, but otherwise its type is implementation-defined. An
implementation shall allow both
(2.1) — a function of () returning int and
(2.2) — a function of (int, pointer to pointer to char) returning int
Secondly you are resetting your unique_ptr to manage a temporary which when unique_ptr gets destroyed at the end of its scope will be deleted which results in undefined behavior. You can't predict/catch errors resulting from undefined behavior.
What you should do (if you really want to use dynamically allocated memory) you can return a pointer to object on the heap:
#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib>
void myterminate()
{
std::cout << "terminate\n";
abort();
}
class data
{
int a;
public:
data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
~data() { std::cout << "dtor " << a << "\n"; }
static data* failure(int a) { return new data(a); }
};
int main()
{
std::set_terminate(myterminate); //terminate is not called
try
{
std::unique_ptr<data> u;
u.reset(data::failure(1));
std::cout << "no worries\n"; //this prints
//destructor called at try-block end and attempt to destruct an invalid memory block.
}
catch (...)
{
std::cout << "caught\n"; //this can not catch the error
}
std::cout << "end\n"; //program crash, will not be called
}
Online code: http://melpon.org/wandbox/permlink/pdiijgDxBshVOYRu
I have following program:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess)
{
cout << "MyError::MyError()\n";
}
MyError::~MyError(void)
{
cout << "MyError::~MyError\n";
}
int main(void)
{
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbye\n";
return 0;
}
Which prints the following:
MyError::MyError()
MyError::~MyError
hi
MyError::~MyError
goodbye
Why is the destructor of the exception (~MyError()) called twice?
I assumed that throw creates a new object, but I do not understand why the class destructor is called.
If you instrument the exception's copy or move constructor, you'll find it's called once before the handler. There's a temporary exception object into which the thrown expression is copied/moved, and it is this exception object to which the reference in the handler will bind. C++14 15.1/3+
So the execution resulting from your code looks something like this (pseudo-C++):
// throw MyError("hi"); expands to:
auto tmp1 = MyError("hi");
auto exceptionObject = std::move(tmp1);
tmp1.~MyError();
goto catch;
// catch expands to:
MyError& exc = exceptionObject;
cout << exc.what() << endl;
// } of catch handler expands to:
exceptionObject.~MyError();
// normal code follows:
cout << "goodbye\n";
Because your compiler is failing to elide the copy from the temporary to the exception object managed by the exception handling mechanism.
Conceptually, MyError("hi") creates a temporary, which will be destroyed at the end of the statement (before the exception can be handled). throw copies the thrown value somewhere else, where it will persist until after the exception has been handled. If the thrown value is a temporary, then a decent compiler should elide the copy and initialise the thrown value directly; apparently, your compiler didn't do that.
My compiler (GCC 4.8.1) does a rather better job:
MyError::MyError()
hi
MyError::~MyError
goodbye
Your exception is being copied. If you instrument the copy ctor, you can see this:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(MyError const &e) : runtime_error("copy") { std::cout << "Copy MyError"; }
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess) {
cout << "MyError::MyError()\n";
}
MyError::~MyError(void) {
cout << "MyError::~MyError\n";
}
int main(void) {
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbye\n";
return 0;
}
Result:
MyError::MyError()
Copy MyError
MyError::~MyError
copy.what()
MyError::~MyError
goodbye