Writing custom exceptions in C++ [closed]
Asked Answered
J

3

7

I am coming from a Ruby and Java background and have recently begun exploring C++.

While my initial attempts at creating custom exceptions by simply subclassing exception class failed with obscure, I found the following example posted on a site:

class Exception : public exception
{
public:
  Exception(string m="exception!") : msg(m) {}
  ~Exception() throw() {}
  const char* what() const throw() { return msg.c_str(); }

private:
  string msg;
};

My understanding of semantics of C++ is not very mature at the moment, and I would like to have a better understanding of what is going on here.

In the statement const char* what() const throw() what does the part const throw() do, and what kind of programming construct is it?

Also, what is the purpose and intent of throw() in the destructor specification ~Exception() and why do I need to have a destructor specification although I don't need it do something in particular? Shouldn't the destructor inherited from exception be sufficient?

Janessajanet answered 6/11, 2012 at 20:23 Comment(4)
const and throw() are two different, unrelated things.Necessity
There's too many questions in here, you'll need to break them up and research them separately.Fiche
You definitely need to read some good C++ books.Bebe
You should probably inherit from std::runtime_error rather than std::exception. Then you don't need to have your member msg or define what() or a destructor. class Exception : public std::runtime_error { public: Exception(string m="exception!") :std::runtime_error(m) {}};Play
J
13

const after a method declares that the method does not mutate the object. (There are exceptions, and generally it's used to mean "does not mutate the object in an externally-visible way.)

The throw() after the method declaration is an exception specification; it's similar to the throws E1, E2 exception specifications that you see in Java. However, in C++, exception specifications are not checked at compilation-time and are generally considered to be mostly useless (they are now deprecated). throw() is the only somewhat useful form, meaning that the function declares that it must not throw an exception (and if it does, it's a logical error, and the program will invoke an unexpected exception handler, by default terminating the program).

The destructor is explicitly declared because if left unspecified, the compiler will generate a destructor that invokes the base class destructor, and the compiler-generated destructor will not use a throw() exception specification (despite the fact that throwing exceptions in destructors is never a good idea).

Johniejohnna answered 6/11, 2012 at 20:37 Comment(0)
G
3

You are currently dealing with some style things of C++! So when you want to actually have an exception-object you may use std::exception, which is explained here on cppreference.

But since you could throw and catch everything in C++, you may even define your own exception class or use more basic aspects, e.g.

try  {
    throw("S0M3, M4YB3 CR1PT1C STR1NG!");  
} catch(char const* exceptStr) {  
    SomeFuncThatDecodesTheString(exceptStr); 
}

Your other topics are more a kind of personal style or standard:

  • An empty destructor like ~FooClass() {} is only there two show "I really do nothing!". Sometimes they might also be useful, when you use a strict system for writing your classes (e.g. First the public space, including the standard ctor at first and the standard dtor as the second function ...) to kind of force you (or some other coder) to write into the existing braces/function and therefore not desroying your holy order :)
  • You may write a throw() behind classes for insurance to other people, that the class does only throw exceptions of the types stated in the parantheses. Therefore a function void FooFunc() throw(int,char) should only throw ints and chars. And an empty throw() is just to actually say "Hey coder, I do not throw anything!". You will often find this in the C++ standard library, since you are (mostly) only able to look at the prototypes and not the source. BTW the throw(someType(s)) might be a lie. The function may throw any other type or simply nothing! But don't be a liar, when you use this ;)

EDIT:

I wanted to add, that noexcept can (since C++11) also be used to declare an function, not to throw any exception. This is pretty more comprehensible than throw().

LG ntor

Grainfield answered 6/11, 2012 at 20:30 Comment(8)
You're throwing const char* there, not a string.Jud
Doesn't it get automatically converted, due to the std::string(const char *)-ctor?Grainfield
No, it doesn't. And "S0M3, M4YB3 CR1PT1C STR1NG!" is char*, not const char*.Sphingosine
No, only a limited set of conversions is performed when matching exceptions with their handlers. @Sphingosine Not in C++.Jud
@Jud In C++ too. However you may not change string literals in C++ as it results in undefined behavior. But the type is the same as in C for compatibility reasons.Sphingosine
@Sphingosine The type os string literals is actually char const[n]. Try sizeof("S0M3, M4YB3 CR1PT1C STR1NG!"), it's 28. The conversion to char* has been deprecated for quite some time.Jud
@Jud Oh, it looks that you're right about the type, it's const char[]. But in VS2010 conversion to char* works without any warnings on warning level 4. Could you point me to the version of standard that made that conversion depreciated?Sphingosine
@Sphingosine In C++11 it's mentioned in appendix C - compatibility. I don't have C++03 standard, so I can't tell, but it has been deprecated since then.Jud
S
2

throw() in the destructor specification means that the destructor doesn't throw exceptions. Destructors in C++ should not throw exceptions - here is why.

Destructors in C++ are not inherited. If you don't write your own destructor then compiler will automatically generate a destructor for you. That destructor will call destructor of a base class if such class exists.

const specifier in Exception::what() declaration means that this method may be called for constant objects of type Exception. throw() specifier means the same as for the destructor.

You should get a book about C++, those are very basic questions.

Sphingosine answered 6/11, 2012 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.