What is the proper way to create an exception hierarchy? - c++

I understand that to properly catch exceptions using multiple inheritance I need to use virtual inheritance.
I'm not necessarily advocating the controversial use of multiple inheritance, but I do not want to design systems that make its usage impossible. Please do not distract from this question to advocate or attack the use of multiple inheritance.
So let's say I have the following base exception type:
class BaseException : public virtual std::exception {
public:
explicit BaseException(std::string msg)
: msg_storage(std::make_shared<std::string>(std::move(msg))) { }
virtual const char* what() const noexcept { return msg_storage->c_str(); }
private:
// shared_ptr to make copy constructor noexcept.
std::shared_ptr<std::string> msg_storage;
};
What is the proper way to create an exception hierarchy from BaseException?
My problem lies with constructing the exception types. Ideally every exception just constructs its parent, but this is impossible due to virtual inheritance. One solution would be to construct every parent up the chain:
struct A : public virtual BaseException {
explicit A(const std::string& msg) : BaseException(msg) { }
};
struct B : public virtual A {
explicit B(const std::string& msg, int code)
: BaseException(msg), A(msg), code_(code) { }
virtual int code() const { return code_; }
private:
int code_;
};
struct C : public virtual B {
explicit C(const std::string& msg, int code)
: BaseException(msg), A(msg), B(msg, code) { }
};
But this seems very repetitive and error-prone. Furthermore, this makes it impossible for constructors of exception types to add/change information passed in by their children before passing through to their respective parents.

I have found a reasonable solution that's not broken as far as I can see. It uses a slightly modified base exception type:
struct BaseException : virtual std::exception {
explicit BaseException(std::string msg)
: msg_storage(std::make_shared<std::string>(std::move(msg))) { }
virtual const char* what() const noexcept { return msg_storage->c_str(); }
protected:
BaseException();
private:
std::shared_ptr<std::string> msg_storage;
};
Then the rules are:
Every exception inherits publicly and virtually from its parent exceptions.
Every exception declares a protected default constructor and defines a protected constructor initializing all data members.
Every exception that is supposed to be Constructible defines a public constructor that directly calls the constructors defined in 2 for every ancestor.
All copy constructors should be noexcept.
An example hierarchy using this:
// A regular derived exception.
struct RuntimeError : virtual BaseException {
RuntimeError(std::string msg) : BaseException(std::move(msg)) { }
protected: RuntimeError() { }
};
// Derived exception with data member.
struct OSError : virtual RuntimeError {
OSError(std::string msg, int e) : BaseException(std::move(msg)), e(e) { }
virtual int error_code() const noexcept { return e; }
protected:
OSError();
OSError(int e) : e(e) { }
private:
int e;
};
// Non-constructible exception type.
struct FatalError : virtual RuntimeError {
protected: FatalError() { }
};
// A composed exception type.
struct FatalOSError : virtual FatalError, virtual OSError {
FatalOSError(std::string msg, int e)
: BaseException(std::move(msg)), OSError(e) { }
protected: FatalOSError() { }
};

Related

Calling method from own exception class catched by its base class

I have two functions a() and b(), which are having own exception classes (consecutively a_exc and b_exc) that inherit from std::logic_error.
void a() { (...) throw a_exc(some_val) }
void b() { (...) throw b_exc(some_val) }
class a_exc : public std::logic_error
{
private:
int foo;
public:
a_exc(int val, const std::string& what_msg="Msg.")
: std::logic_error(what_msg), foo(val) {}
void show() { //show foo }
}
class b_exc : public std::logic_error
{
private:
std::string bar;
public:
a_exc(std::string val, const std::string& what_msg="Msg.")
: std::logic_error(what_msg), bar(val) {}
void show() { //show bar }
}
Let's say I have following part of code:
try {
a();
b();
}
catch (const std::logic_error& e)
{
e.what();
// e.show();
}
catch (const std::logic_error& e) catches both a_exc and b_exc. Of course this block cannot use e.show(), because catched obj is std::logic_error.
And here's my problem. I wonder if there is any chance to call show() method in std::logic_error catch block when catched exception was a_exc or b_exc. I know, calling show() is possible if I create separate catch blocks for a_exc and b_exc, but I want to call this method with using just one catch block. Is it possible?
You can, provided that show() is a const member function:
catch (const std::logic_error& e)
{
e.what();
if(const a_exc* a = dynamic_cast<const a_exc*>(&e))
a->show();
else if(const b_exc* b = dynamic_cast<const b_exc*>(&e))
b->show();
}
See it Live on Coliru. Though, it's usually a bad idea to call other functions that may throw in your catch exception handler.
Some thoughts on design.
Querying the type of exception within the catch block is logically no different to simply providing two catch blocks.
To be clear:
catch(X& x)
{
if (dynamic_cast<Y*>(&x)) {
// it's a Y
}
if (dynamic_cast<Z*>(&z)) {
// it's a Z
}
else {
// it's an X
}
}
is logically the same as:
catch(Y& t)
{
// it's a Y
}
catch(Z& z)
{
// it's a Z
}
catch(X& x)
{
// it's an X
}
Except that the second is clearer, more maintainable and resistant to inadvertent slicing on a subsequent copy.
The first is using "code to find code", which is always a maintenance disaster waiting to happen.
Your question raises more questions of its own:
Are a_exc and b_exc two kinds of the same error? If so, this argues for a polymorphic base class, which you can catch in preference to std::logic_error
Do you really need the show() method? Can you simply build the what string in the constructor, and pass this string to the constructor of std::logic_error? If this is at all possible, it is the route I would recommend. The moment you start adding special interfaces to exceptions, you pollute your entire code base with the necessity of knowing about this interface. If you're writing a library, you've now polluted every application that uses your library.
Assuming you do need show, and a_exc and b_exc really are two kinds of the same error, we can still avoid polymorphism. Perhaps we can shore the 'show' message as a string, and build it in the constructor. Now it's just data. No fuss, no complication.
(complete) example using polymorphic base class (a_exc an b_exc are kinds of the same thing)
#include <stdexcept>
#include <string>
struct showable_logic_error : std::logic_error
{
using std::logic_error::logic_error;
virtual void show() const = 0;
};
class a_exc : public showable_logic_error
{
private:
int foo;
public:
a_exc(int val, const std::string& what_msg="Msg.")
: showable_logic_error(what_msg)
, foo(val)
{}
void show() const override
{
//show foo
}
};
class b_exc : public showable_logic_error
{
private:
std::string bar;
public:
b_exc(std::string val, const std::string& what_msg="Msg.")
: showable_logic_error(what_msg)
, bar(val)
{}
void show() const override
{ //show bar
}
};
void a() { throw a_exc(1); }
void b() { throw b_exc("b"); }
int main()
{
try
{
a();
}
catch(showable_logic_error const& e)
{
e.show();
}
}
complete example in which no polymorphism is required:
#include <stdexcept>
#include <string>
#include <sstream>
struct message_builder
{
template<class T>
static std::string build_what(const std::string& whatstr, T&& info)
{
std::ostringstream ss;
ss << whatstr << " : " << info;
return ss.str();
}
};
class a_exc
: public std::logic_error
, private message_builder
{
public:
a_exc(int val, const std::string& what_msg="Msg.")
: std::logic_error(build_what(what_msg, val))
{}
};
class b_exc
: public std::logic_error
, private message_builder
{
private:
std::string bar;
public:
b_exc(std::string val, const std::string& what_msg="Msg.")
: std::logic_error(build_what(what_msg, std::move(val)))
, bar(val)
{}
};
void a() { throw a_exc(1); }
void b() { throw b_exc("b"); }
int main()
{
try
{
a();
}
catch(std::logic_error const& e)
{
e.show();
}
}
You should consider creating a derived type:
struct show_exc : public std::logic_error
{
virtual void show() = 0;
};
class a_exc : public show_exc
{
int foo_;
public:
virtual void show() override { /*...*/ };
};
and then use a distinguishing catch:
catch (const show_exc& e) {
// ..
}
catch (const std::logic_error& e) {
// ..
}

Odd C++ accessing private member issue

I have this piece of code:
class object
{
public:
virtual ~object(){ }
bool equals(const object& J)const
{
return &J == this;
}
int operator==(const object& J)const
{
return equals(J);
}
virtual int getHash()const;
virtual void getType()const;
void* operator new(size_t size)
{
void*mem = malloc(size);
return mem;
}
};
class notcopyable
{
private:
notcopyable(const notcopyable&){}
notcopyable& operator=(const notcopyable&){}
public:
notcopyable(){}
};
class exception :
public object,public notcopyable
{
private:
public:
virtual ~exception();
virtual const char* info();
};
class exception_not_implemented :
public exception
{
public:
exception_not_implemented()
{
}
virtual const char* info()
{
return "exception_not_implemented: ";
}
};
class exception_oob :public exception
{
public:
exception_oob()
{
}
virtual const char* info()
{
return "Index out of boundary";
}
};
There are two functions throw exception_not_implemented:
void object::getType()const
{
throw exception_not_implemented();
}
int object::getHash()const
{
throw exception_not_implemented();
}
And getting this error:
error C2248: 'js::notcopyable::notcopyable' : cannot access private member declared in class 'js::notcopyable'
The output of the compiler says:
This diagnostic occurred in the compiler generated function 'js::exception::exception(const js::exception &)'
If I delete the two throw shown above, it works well. But the same error doesn't happens to exception_oob. I can't figure out why.
You can temporarily add a private copy constructor declaration, which will generate an error at the point where a copy is being made. Then you can fix that code to not make copies.
The error should happen at other place where you call the (private) copy constructor.
For example:
Exception a;
Exception b = a; // error : cannot access private member ...

Exception does not get caught

I have a base and a derived exceptions, public inner classes of store:
//base class - ProductException
class ProductException: exception
{
protected:
const int prodNum;
public:
//default+input constructor
ProductException(const int& inputNum=0);
//destructor
~ProductException();
virtual const char* what() const throw();
};
//derived class - AddProdException
class AddProdException: ProductException
{
public:
//default+input constructor
AddProdException(const int& inputNum=0);
//destructor
~AddProdException();
//override base exception's method
virtual const char* what() const throw();
};
this function which throws the derived exception:
void addProduct(const int& num,const string& name) throw(AddProdException);
void Store::addProduct( const int& num,const string& name )
{
//irrelevant code...
throw(AddProdException(num));
}
and a function which calls the function and tries to catch an exception:
try
{
switch(op)
{
case 1:
{
cin>>num>>name;
st.addProduct(num,name);
break;
}
}
}
...
catch(Store::ProductException& e)
{
const char* errStr=e.what();
cout<<errStr;
delete[] errStr;
}
The derived class should get caught, but I keep getting the error "unhandled exception". Any ideas why? Thanks!
The reason is that AddProdException is not a ProductException, because you are using private inheritance:
class AddProdException: ProductException {};
You need to use public inheritance:
class AddProdException: public ProductException {};
The same applies to ProductException and exception, assuming the latter is an std::exception.
Without the public keyword, inheritance is considered private by default. This means AddProdException is-not a ProductException. Use public inheritance like so:
class AddProdException : public ProductException
{
public:
//default+input constructor
AddProdException(const int& inputNum=0);
//destructor
~AddProdException();
//override base exception's method
virtual const char* what() const throw();
};
Also, inherit from std::exception publicly in ProductException as well, otherwise you won't be able to catch std::exceptions either (or even better, from std::runtime_error).

virtual method in exceptions

I have made my own exception class which derives from runtime_error and is getting an int in the c'tor.
I would like to make a base class for this exception, in order to use polymorphism, so I could catch only the base class and basically I would be catching the derived class, and then call .what() method from it.
So, this is the base class: (ofc in another cpp file I got baseException::~baseException(){})
class baseException
{
virtual ~baseException()=0 {}
virtual const char* what()=0;
};
And this is the derived class:
class myException: public runtime_error, public baseException
{
public:
myException(int): runtime_error("Error occured") {}
const char* what() {return runtime_error::what();}
};
But when in the main I write:
catch(baseException* x)
{
cout<<x->what();
}
it just skips it and does not enter the block, even though myException inherits from baseException. Any suggests?
You should catch exceptions by reference (or const reference), not by pointer.
Your baseException doesn't have the what method, you should probably just derive baseException from runtime_error.
class baseException : public runtime_error
{
public:
baseException(const std::string& what) : runtime_error(what) {}
};
and then
class myException: public baseException
{
public:
myException(int): baseException("Error occured") {}
};
Although I prefer the following idiom:
class myException: public baseException
{
public:
myException(int x): baseException(getWhatMessage(x)) {}
private:
static std::string getWhatMessage(int x) { /*generate the message*/ }
};
On the catch part. If you throw using throw myException(5), then you should catch like this
catch(baseException& x)
{
cout<<x.what();
}
Your catching a reference to a baseException object; therefor you just know the methods of that class. baseException does not have a member called what() though. This causes the error.
Make baseException derive from runtime_error or catch a myException directly.
Edit:
This snippet shows that theres absolutely no reason why pointers shouldnt work together with exceptions:
#include <iostream>
#include <string>
class A {
public:
virtual int test() = 0;
};
class B : public A {
public:
virtual int test() {
return 42;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
try {
throw new std::string("foo");
} catch (std::string* ecx){
std::cout << *ecx << std::endl;
}
try {
throw new B();
} catch (A* ecx) {
std::cout << ecx->test() << std::endl;
}
}
Output:
foo
42
UPDATE: this answer was based on the original version of the question. It now seems that the problem isn't calling what() (as you've worked around that by redeclaring it in your base class). The problem is simply that you're trying to catch a pointer and (I guess) throwing a value; the solution is to catch by reference:
catch (myException const & ex) {
std::cerr << ex.what() << std::endl;
}
(assuming you fix your declaration of what() to be const; if for some reason you really need it to be non-const, then remove const from the catch line).
ORIGINAL ANSWER describing how to call what() if it isn't declared in baseException:
I want to catch baseException*
You'd be better off catching baseException const &; there's no sensible way to throw a pointer.
and call their .what() methods
If you want to call what() , then you might be better off catching std::exception const & instead; unless you also want some functionality from your base class. In that case, perhaps your base class should inherit from std::runtime_error; or perhaps it should inherit from std::exception, in which case your myException type would need to use virtual inheritance.
If you really want to access what() from your classes as they stand, then you'll need to cross-cast to std::exception:
catch (myException const & ex) {
std::cerr << dynamic_cast<std::exception const &>(ex).what() << '\n';
}

Simulating a virtual static member of a class in c++?

Is there anyway to have a sort of virtual static member in C++?
For example:
class BaseClass {
public:
BaseClass(const string& name) : _name(name) {}
string GetName() const { return _name; }
virtual void UseClass() = 0;
private:
const string _name;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass("DerivedClass") {}
virtual void UseClass() { /* do something */ }
};
I know this example is trivial, but if I have a vector of complex data that is going to be always the same for all derived class but is needed to be accessed from base class methods?
class BaseClass {
public:
BaseClass() {}
virtual string GetName() const = 0;
virtual void UseClass() = 0;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
virtual string GetName() const { return _name; }
virtual void UseClass() { /* do something */ }
private:
static const string _name;
};
string DerivedClass::_name = "DerivedClass";
This solution does not satify me because I need reimplement the member _name and its accessor GetName() in every class. In my case I have several members that follows _name behavior and tenths of derived classes.
Any idea?
Here is one solution:
struct BaseData
{
const string my_word;
const int my_number;
};
class Base
{
public:
Base(const BaseData* apBaseData)
{
mpBaseData = apBaseData;
}
const string getMyWord()
{
return mpBaseData->my_word;
}
int getMyNumber()
{
return mpBaseData->my_number;
}
private:
const BaseData* mpBaseData;
};
class Derived : public Base
{
public:
Derived() : Base(&sBaseData)
{
}
private:
static BaseData sBaseData;
}
BaseData Derived::BaseData = { "Foo", 42 };
It seems like the answer is in the question - the method you suggested seems to be the right direction to go, except that if you have a big number of those shared members you might want to gather them into a struct or class and past that as the argument to the constructor of the base class.
If you insist on having the "shared" members implemented as static members of the derived class, you might be able to auto-generate the code of the derived classes. XSLT is a great tool for auto-generating simple classes.
In general, the example doesn't show a need for "virtual static" members, because for purposes like these you don't actually need inheritance - instead you should use the base class and have it accept the appropriate values in the constructor - maybe creating a single instance of the arguments for each "sub-type" and passing a pointer to it to avoid duplication of the shared data. Another similar approach is to use templates and pass as the template argument a class that provides all the relevant values (this is commonly referred to as the "Policy" pattern).
To conclude - for the purpose of the original example, there is no need for such "virtual static" members. If you still think they are needed for the code you are writing, please try to elaborate and add more context.
Example of what I described above:
class BaseClass {
public:
BaseClass(const Descriptor& desc) : _desc(desc) {}
string GetName() const { return _desc.name; }
int GetId() const { return _desc.Id; }
X GetX() connst { return _desc.X; }
virtual void UseClass() = 0;
private:
const Descriptor _desc;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(Descriptor("abc", 1,...)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass("Wowzer", 843,...) {}
virtual void UseClass() { /* do something */ }
};
I'd like to elaborate on this solution, and maybe give a solution to the de-initialization problem:
With a small change, you can implement the design described above without necessarily create a new instance of the "descriptor" for each instance of a derived class.
You can create a singleton object, DescriptorMap, that will hold the single instance of each descriptor, and use it when constructing the derived objects like so:
enum InstanceType {
Yellow,
Big,
BananaHammoc
}
class DescriptorsMap{
public:
static Descriptor* GetDescriptor(InstanceType type) {
if ( _instance.Get() == null) {
_instance.reset(new DescriptorsMap());
}
return _instance.Get()-> _descriptors[type];
}
private:
DescriptorsMap() {
descriptors[Yellow] = new Descriptor("Yellow", 42, ...);
descriptors[Big] = new Descriptor("InJapan", 17, ...)
...
}
~DescriptorsMap() {
/*Delete all the descriptors from the map*/
}
static autoptr<DescriptorsMap> _instance;
map<InstanceType, Descriptor*> _descriptors;
}
Now we can do this:
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.BananaHammoc)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.Yellow)) {}
virtual void UseClass() { /* do something */ }
};
At the end of execution, when the C runtime performs uninitializations, it also calls the destructor of static objects, including our autoptr, which in deletes our instance of the DescriptorsMap.
So now we have a single instance of each descriptor that is also being deleted at the end of execution.
Note that if the only purpose of the derived class is to supply the relevant "descriptor" data (i.e. as opposed to implementing virtual functions) then you should make do with making the base class non-abstract, and just creating an instance with the appropriate descriptor each time.
I agree with Hershi's suggestion to use a template as the "base class". From what you're describing, it sounds more like a use for templates rather then subclassing.
You could create a template as follows ( have not tried to compile this ):
template <typename T>
class Object
{
public:
Object( const T& newObject ) : yourObject(newObject) {} ;
T GetObject() const { return yourObject } ;
void SetObject( const T& newObject ) { yourObject = newObject } ;
protected:
const T yourObject ;
} ;
class SomeClassOne
{
public:
SomeClassOne( const std::vector& someData )
{
yourData.SetObject( someData ) ;
}
private:
Object<std::vector<int>> yourData ;
} ;
This will let you use the template class methods to modify the data as needed from within your custom classes that use the data and share the various aspects of the template class.
If you're intent on using inheritance, then you might have to resort to the "joys" of using a void* pointer in your BaseClass and dealing with casting, etc.
However, based on your explanation, it seems like you need templates and not inheritance.
#Hershi: the problem with that approach is that each instance of each derived class has a copy of the data, which may be expensive in some way.
Perhaps you could try something like this (I'm spit-balling without a compiling example, but the idea should be clear).
#include <iostream>
#include <string>
using namespace std;
struct DerivedData
{
DerivedData(const string & word, const int number) :
my_word(word), my_number(number) {}
const string my_word;
const int my_number;
};
class Base {
public:
Base() : m_data(0) {}
string getWord() const { return m_data->my_word; }
int getNumber() const { return m_data->my_number; }
protected:
DerivedData * m_data;
};
class Derived : public Base {
public:
Derived() : Base() {
if(Derived::s_data == 0) {
Derived::s_data = new DerivedData("abc", 1);
}
m_data = s_data;
}
private:
static DerivedData * s_data;
};
DerivedData * Derived::s_data = 0;
int main()
{
Base * p_b = new Derived();
cout getWord() << endl;
}
Regarding the follow-up question on deleting the static object: the only solution that comes to mind is to use a smart pointer, something like the Boost shared pointer.
It sounds as if you're trying to avoid having to duplicate the code at the leaf classes, so why not just derive an intermediate base class from the base class. this intermediate class can hold the static data, and have all your leaf classes derive from the intermediate base class. This presupposes that one static piece of data held over all the derived classes is desired, which seems so from your example.