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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lorefnon
  • 12,875
  • 6
  • 61
  • 93
  • `const` and `throw()` are two different, unrelated things. – chris Nov 06 '12 at 20:24
  • There's too many questions in here, you'll need to break them up and research them separately. – djechlin Nov 06 '12 at 20:30
  • 1
    You definitely need to read [some good C++ books](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Bo Persson Nov 06 '12 at 20:50
  • 3
    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) {}};` – Martin York Nov 06 '12 at 20:50

3 Answers3

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).

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
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

Peter Wildemann
  • 465
  • 4
  • 13
  • 1
    You're throwing `const char*` there, not a `string`. – jrok Nov 06 '12 at 20:44
  • Doesn't it get automatically converted, due to the `std::string(const char *)`-ctor? – Peter Wildemann Nov 06 '12 at 20:52
  • No, it doesn't. And `"S0M3, M4YB3 CR1PT1C STR1NG!"` is `char*`, not `const char*`. – jimvonmoon Nov 06 '12 at 20:59
  • No, only a limited set of conversions is performed when matching exceptions with their handlers. @jimvonmoon Not in C++. – jrok Nov 06 '12 at 20:59
  • @jrok 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. – jimvonmoon Nov 06 '12 at 21:09
  • 2
    @jimvonmoon 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. – jrok Nov 06 '12 at 21:14
  • @jrok 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? – jimvonmoon Nov 06 '12 at 21:25
  • @jimvonmoon 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. – jrok Nov 06 '12 at 21:58
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.

jimvonmoon
  • 342
  • 3
  • 12