Friday, 22 March 2013

noexcept

If you've been developing C++ over the last several years you'll probably be aware of exception specifications, and probably not for good reasons. The feature was variably implemented across popular compilers, ranging from "not at all implemented", through to "we'll just do what we like", which led to an unfortunate situation whereby an ANSI-specified feature could not be relied upon as portable code. So far, so disappointing.

The other major problem with exception specifications is that they don't actually help a great deal and their behaviour could be a little... surprising. Their (official) effect was a mixture of compile-time and run-time behaviours, which conspired to not really help all that much while affecting performance more than one might expect.

Consider this sample, which compiles without warning (well, apart from unref'd variables):


 class A {};  
 class B {};  
 class ExceptionTest  
 {  
 public:  
      void throwsB() throw(A)  
      {  
           // whoops, wrong exception spec  
           throw B();  
      }  
 };  
 int main()  
 {  
      ExceptionTest e;  
      try  
      {  
           // expecting a B  
           e.throwsB();  
      }  
      catch(B &b)  
      {  
      }  
      return 0;  
 }  

So... we get no compile-time protection against throwing incorrect exceptions. What we do get is run-time checking, so when an invalid exception is thrown, unexpected() gets called, which by default results in terminate() being called. This behaviour can be customised, but that's not important here.

There is some limited compile-time checking. For example, a function overriding a virtual function can't declare an exception specification that differs from the function it is overriding. Wow. Anyway, exception specifications are dead, so what now? What we really want is some kind of composable, logical compile-time checking that alerts the developer to bugs that would otherwise manifest at run-time. We want something analogous to const correctness.

The C++11 offering is noexcept, and it's similar and it's different. It's similar in that what appears to be a guarantee or a promise is nothing of the sort. In fact, code that violates the noexcept specifier will compile happily and then just make a call to std::unexpected() (and probably to std::terminate()) when the exception is thrown. Hey, at least no exceptions escaped! The reason for this is discussed at length and in excellent detail in Andrzej's C++ blog here

So, is this a rejection of static checking of exceptions? No. It sounds like the standards committee have the same aspiration as the rest of us: to get the compiler to help us by raising an error when an exception could be emitted from some function that has promised not to.

Why does noexcept exist? Currently, it's another compiler hint. If the compiler can rely upon no exception escaping from a function (one way or another), certain optimisations become possible. In the future, maybe compiling identical code with a compiler implementing the next major standard will check your exception guarantees. noexcept has other minor advantages, for which I will again direct you to Andrzej's blog rather than reproducing his good work here.

Wednesday, 16 January 2013

std::current_exception()

Ok, this is a very nice idea, and also very simple. std::current_exception returns a std::exception_ptr to the exception currently being handled by a catch{} block. The following snippet shows it in action quite well, but I don't expect that this kind of thing will take off for current_exception. It might even be something of an antipattern in its current form:
 try  
 {  
  someFunction();  
 }  
 catch(...)  
 {  
  auto exPtr = std::current_exception();  
  /* now we have an exception pointer to the current exception... */  
 }  

This is all well and good, but what's the point? In search of that we look at bit deeper at std::exception_ptr, which provides shared ownership semantics for exceptions in a similar fashion to shared ownership of objects provided by std::shared_ptr. Exception pointers can be created from exceptions:
 try  
 {  
  someFunction()  
 }  
 catch(std::exception &ex)  
 {  
  std::exception_ptr exPtr = std::make_exception_ptr(ex);  
  /* now we have an exception ptr... */
 }  

The C++11 standard says that make_exception_ptr works roughly like this:
 template<class E> exception_ptr make_exception_ptr(E e) noexcept  
 {  
  try   
  {  
   throw e;  
  }   
  catch(...)  
  {  
   return current_exception();  
  }  
 }  

It can't be the case that std::current_exception exists only to service std::make_exception_ptr, so what's all this about? The answer shouldn't surprise you: threading. Exceptions are notoriously bad at cross-thread error propagation and until C++11 there's been no simple cross-platform way of doing this. Sure, you could catch your exception, stash it somewhere and let another thread rethrow it to code that can do something about it, but the problem is that you need to manually account for all types of exception that can be thrown. This doesn't scale well and leaves you responsible for actively managing the lifetime of your exception object.

Using
std::current_exception() to get a  std::exception_ptr to anything that's been thrown (and remember, you can throw just about anything in C++!), you can store a container of those exception pointers in one thread and use std::rethrow_exception to propagate them again in another thread. This is possible because, although the precise definition of std::exception_ptr is unspecified, it is untemplated and therefore opaque enough to store in a homogeneous container. As soon as your exception is no longer referenced by at least one std::exception_ptr, its lifetime ends and the resources are freed up. 

What could be simpler?

The "transporting exception across the thread boundary" pattern is implemented in this example from Microsoft.

Monday, 14 January 2013

std::to_string()

Starting simple, I was really pleased and a little surprised to see to_string (and its sibling, to_wstring) pop up. It's a feature that we've really needed for more time than I care to consider and it removes the need for the fairly foul: 

 char buff[12] = {0};  
 sprintf(buff, "%d", INT_MIN);  
 /* convert to std::string if we like */  

or the moderately foul:


 std::ostringstream mystream;  
 mystream << INT_MIN;  
 std::string s = mystream.str();  

I'm not saying there aren't proper uses for sprintf or stringstream, it's just that the above seems such a waste of time when you consider Python's str() or even C#'s versatile Convert.ToString(). Neither of my examples are very expressive and the first gets even worse if you're developing for a Microsoft platform and you have to start considering sprintf_s and the like.

std::to_string is long overdue and extremely simple to use:


 float f = 3.14;  
 std::string piString = std::to_string(f);  

What could be easier than that? No worrying about buffer sizes, no baroque format string incantations, no stringstream wastes. That ends the first real post. If anyone posts comments, I promise to read them. Is anybody out there?

Hi!

I'm a big fan of the new(ish) C++11 standard. It's not that I think it patches the problems with previous C++ standards: it's still more than possible to leak memory, construct truly horrible deadlock scenarios and accidentally take a copy of vast amounts of data. The difference is that it enables and encourages a way of writing C++ code that dramatically reduces the likelihood of you encountering the above situations. Please don't believe me, there's lots written on this subject by people far more intelligent than me and I hope you have the time to check it out.

I was inspired to have a go at writing this technical blog by the sheer number of surprising things that crop up when I'm watching the experts discuss the new headline C++11 features. I'm talking mostly about the types added to the standard library, some of which are incredibly feature rich and expressive and have received almost no coverage online. Also, there is a distinct paucity of examples that I might be able to begin to address here.

So that's it. I'm going to give it a go. At some point, sooner or later, I will run out of things that surprise me in C++11 and then I'll just stop. Until then, I hope these posts are of at least some small utility to some of you.