October 2010 C++ Standards Committee Mailing

Thursday, 21 October 2010

The October 2010 mailing for the C++ Standards Committee was published earlier this week. This is the pre-meeting mailing for the November 2010 committee meeting.

As well as the usual core and library issues lists, this mailing also includes a Summary of the status of the FCD comments, along with a whole host of papers attempting to address some the remaining FCD comments.

To move or not to move

The big issue of the upcoming meeting is looking to be whether or not the compiler should implicitly generate move constructors and move assignment operators akin to the copy constructors and copy assignment operators that are currently auto generated. The wording in the FCD requires this, but people are concerned that this will break existing code when people start using their code with a C++0x compiler and library. There are two papers on the subject in the mailing: N3153: Implicit Move Must Go by Dave Abrahams, and N3174: To move or not to move by Bjarne Stroustrup.

There seems to be consensus among committee members that the FCD requires compilers to generate the move constructor and move assignment operator in cases that will break existing code. The key question is whether the breakage can be limited by restricting the cases in which the move members are implicitly generated, or whether implicit generation should be abandoned altogether. The various options are explained very clearly in the papers.

Exceptions and Destructors

N3166: Destructors default to noexcept is another potentially controversial issue. It is generally acknowledged that throwing exceptions from destructors is a bad idea, not least because this leads to termination if the destructor is invoked whilst the stack is being unwound due to another exception. Herb Sutter wrote about this way back in 1998 when the original C++ standard was hot off the presses, in GotW #47: Uncaught Exceptions.

The proposal in the paper comes from a Finnish comment on the FCD, and is quite simple: by default all destructors are assumed to be marked noexcept(true) (which is the new way of saying they cannot throw an exception, similar to an exception specification of throw()), unless they explicitly have a non-empty exception specification or are marked noexcept(false).

Since it is generally good practice not to throw from a destructor, you'd think this would be uncontroversial. Unfortunately it is not the case — there are currently situations where throwing from a destructor has defined behaviour, and even does exactly what people want. The example most frequently cited is the SOCI project for accessing databases from C++. This library provides an easy syntax for constructing SQL queries using the << operator. The operator builds a temporary object which executes the SQL in the destructor. If the SQL is invalid, or executing it causes an exception for any other reason then the destructor throws. Changing destructors to be noexcept(true) by default will make such code terminate on a database error unless the destructor is updated to declare that it can throw exceptions. Working code with defined behaviour is thus broken when recompiled with a C++0x compiler.

Concurrency-related papers

There are 3 concurrency-related papers in this mailing, which I've summarised below.

N3152: Progress guarantees for C++0x (US 3 and US 186)

The FCD does not make any progress guarantees when multiple threads are used. In particular, writes made by one thread do not ever have to become visible to other threads, and threads aren't guaranteed ever to actually run at all. This paper looks at the issues and provides wording for minimal guarantees.

N3164: Adjusting C++ Atomics for C Compatibility

This is an update to N3137 from the last mailing, which provides detailed wording updates for the required changes to regain compatibility with C1X atomics.

N3170: Clarifying C++ Futures

There were a few FCD comments from the US about the use of futures; this paper outlines all the issues and potential solutions. The proposed changes are actually fairly minor though:

  • future gains a share() member function for easy conversion to the corresponding shared_future type;
  • Accessing a shared_future for which valid() is false is now required to throw an exception rather than be undefined behaviour;
  • atomic_future is to be removed;

A few minor changes have also been made to the wording to make things clearer.

If you have any opinions on any of the papers listed here, or the resolution of any NB comments, please add them to the comments for this post.

Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: , , ,

| Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.

4 Comments

Hi, I have a comment to C++ Standard Core Language Active Issue 1168 (Additional reasons to call std::terminate), which is a response to NB comment GB 47. It proposes the following text:

"In some situations exception handling must be abandoned for less subtle error handling techniques. [Note: These situations are: * ... the list goes ... * when the destructor or the copy assignment operator is invoked on a std::thread object that refers to a joinable thread [...]" Well we know what it means, but I think there is a loic error in this text. The header of the list says that the situations listed describe when exception handling must be abandoned. So, situation in each bullet implies that exception handling was in progress. But in case of the situation where we copy a joinable std::thread, there is no exception handling in progress.The situation can also happen if we switch off exceptions in our compiler. The last bullet just does not fit into the list. It should be removed, or even better it should be left there, but the header of the list should be changed to something like: "In some situations, program execution should be abandoned and error handling techniques less subtle than exception handling need to be employed." This makes sense as with the inclusion of this behavior of std::thread, the C++ standard opened a new feture: not only do we terminate on exception handling mechanism failure, but also upon some application design errors. There may be moreof these situations in the future once we have the precedent. (A good precedent, by the way.)

by Andrzej Krzemienski at 21:15:47 on Friday, 22 October 2010

There is yet one other issue, and that's initializer lists. Bjarne's paper ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3139.pdf ) outlines the problem with this new construct. I would expect there will some discussion at the Batavia meeting about this, as it's still not clear what to do here that won't be just one more patch rule to the other lookup rules.

by Gary Powell at 01:04:31 on Saturday, 23 October 2010

As far as I can tell, there is no way to use initializer lists to do move construction.

I would like to be able to say something like

typedef std::unique_ptr<int> ptr

int *p, *q, *r; std::vector<ptr> vec{{p},{q},{r}}; or int *p, *q, *r; std::vector<ptr> vec{ptr{p},ptr{q},ptr{r}}; or ptr p, q, r; std::vector<ptr> vec{std::move(p),std::move(q),std::move(r)};

by Tom Prince at 03:50:53 on Thursday, 04 November 2010

This is in response to national body comment DE 8, which is has a defect number 1125 (Unclear definition of &#8220;potential constant expression&#8221;). THe question boils down to answering if the word "arbitrary" means "there exists a value for which the result is a constant expression" or "for all possible values, the result needs to be a constant expression". If we choose the latter answer functions like constexpr int f(int x, int y){ return x + y; } become invalid. Nearly every constexpr function is invalid. If we choose the former option we render all functions like constexpr int f2(bool v) { return v ? throw 0 : 0; } valid. There are possibly some middle-ground solutions, however, unless there exists some serious technical difficulty, I would propose to adapt a solution that allows throwing from constexpr function; it is very useful for reporting errors at both compile-time and runtime. Consider this example.

constexpr int dayOfMonth( int d ) { return (d < 1 || d > 31) ? (throw InvalidDayOfMonth, 0), d; }

This function at compile-time works for arguments between 1 and 31, and fails to compile for other values (almost a static_assert). At run-time it works for arguments between 1 and 31 and throws exception for other values. In contrast, for the other interpretation of the word "arbitrary" we have no mechanism for communicating errors neither at compile time, nor at run-time.

If the throw example works, it enables us to implement compile-time arbitrary string processing, the feature that variadic templates and user-defined literals failed to deliver. The method is briefly described here : https://groups.google.com/group/comp.std.c++/browse_thread/thread/718da390a710e9cc?hl=en

by Andrzej Krzemienski at 08:58:00 on Tuesday, 09 November 2010

Add your comment

Your name:

Your URL:

Email address:

Person or spambot?

Your comment: