Blog Archive for / cplusplus /
Copying Exceptions in C++0x
Tuesday, 15 March 2011
One of the new features of C++0x is the ability to capture
exceptions in a std::exception_ptr and rethrow them later
without knowing what type they are. This is particularly
useful, as it allows you to propagate the exceptions across threads
— you capture the exception in one thread, then pass the
std::exception_ptr object across to the other thread, and
then use std::rethrow_exception() on that other thread to
rethrow it. In fact, the exception propagation facilities
of std::async, std::promise
and std::packaged_task are build on this feature.
To copy or not to copy
The original proposal for the feature required that the exception
was copied when it was captured
with std::current_exception, but under pressure from
implementors that use
the "Itanium
ABI" (which is actually used for other platforms too, such as
64-bit x86 linux and MacOSX), the requirement was lessened to allow
reference counting the exceptions instead. The problem they cited
was that the ABI didn't store the copy constructor for exception
objects, so when you called std::current_exception()
the information required to copy the object was not present.
Race conditions
Unfortunately, no-one foresaw that this would open the door for race conditions, since the same exception object would be active on multiple threads at once. If any of the thread modified the object then there would be a data race, and undefined behaviour.
It is a common idiom to catch exceptions by non-const reference in
order to add further information to the exception, and then rethrow
it. If this exception came from another thread (e.g. through use
of std::async), then it may be active in multiple
threads at once if it was propagated
using std::shared_future, or even just
with std::exception_ptr directly. Modifying the
exception to add the additional information is thus a data race if
done unsynchronized, but even if you add a mutex to the class you're
still modifying an exception being used by another thread, which is
just wrong.
Race conditions are bad enough, but these race conditions are implementation-dependent. The draft allows for the exceptions to be copied (as originally intended), and some compilers do that (e.g. MSVC 2010), and it also allows for them to be reference counted, and other compilers do that (e.g. gcc 4.5 on linux). This means that code that is well-defined and race-condition-free on MSVC 2010 might be buggy, and have data races when compiled with gcc 4.5, but the compiler will not (and cannot) warn about it. This is the nastiest of circumstances — race conditions silently added to working code with no warning.
Dealing with the issue
BSI raised an issue on the FCD about this when it came to ballot time. This issue is GB-74, and thus must be dealt with one way or the other before the C++0x standard is published (though sadly, "being dealt with" can mean that it is rejected). This is being dealt with by LWG, so is also listed as LWG issue 1369, where there is a more complete proposed resolution. Unfortunately, we still need to convince the rest of the committee to make this change, including those implementors who use the Itanium ABI.
Extending the ABI
Fortunately, the Itanium ABI is designed to be extensible in a
backwards-compatible manner. This means that existing code compiled
with an existing compiler can be linked against new code compiled
with a new compiler, and everything "just works". The old code only
uses the facilities that existed when it was written, and the new
code takes advantage of the new facilities. This means that the
exception structures can be enhanced to add the necessary
information for copying the exception (the size of the object, so
we can allocate memory for it, and the address copy constructor, or
a flag to say "use memcpy".) This isn't quite perfect,
as exceptions thrown from old code won't have the new information,
but provided we can detect that scenario all is well, as the
standard draft allows us to throw std::bad_exception
in that case.
I have written a patch for gcc 4.5.0 which demonstrates this as a proof of concept.
This patch extends the exception structures as allowed by the ABI
to add two fields: one for the object size, and one for the copy
constructor. Exceptions thrown by old code will have a size of zero
(which is illegal, so acts as a flag for old code), and thus will be
captures as std::bad_exception when stored in
a std::exception_ptr. Trivially copyable objects such
as a plain int, or a POD class will have
a NULL copy constructor pointer but a valid size,
indicating that they are to be copied using memcpy.
To use the patch, get the sources for gcc 4.5.0 from your
local GCC mirror,
unpack them, and apply the patch. Then compile the patched sources
and install your new gcc somewhere. Now, when you compile code that
throws exceptions it will use the
new __cxa_throw_copyable function in place of the
old __cxa_throw function to store the requisite
information. Unless you link against the right support code then
your applications won't link; I found I had to use
the -static command line option to force the use of the
new exception-handling runtime rather than the standard platform
runtime.
/opt/newgcc/bin/g++ -std=c++0x -static foo.cpp -o foo
Note that if the copy constructor of the exception is not thread
safe then there might still be an issue when
using std::exception_ptr, as my patch doesn't include a
mutex. However, this would be an easy extension to make now the
proof of concept has been done. I also expect that there are cases
that don't behave quite right, as I am far from being an expert on
the gcc internals.
Hopefully, this proof of concept will help convince the rest of the C++ committee to accept GB-74 at the meeting in Madrid next week.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, C++0x, WG21, Exceptions, Copying, exception_ptr, rethrow_exception
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
November 2010 C++ Standards Committee Mailing
Tuesday, 07 December 2010
The November 2010 mailing for the C++ Standards Committee was published last week. This is the post-meeting mailing for the November 2010 committee meeting.
As well as the usual core and library issues lists, this mailing also includes an updated summary of the status of the FCD comments, along with a whole host of papers attempting to address some the remaining FCD comments and a new C++0x working draft.
To move or not to move
In my blog post on the October mailing, I mentioned that the implicit generation of move constructors was a big issue. I even contributed a paper with proposed wording for removing implicit move generation from the draft — with expert core wording guidance from Jason Merrill, this became N3216. My paper was just to give the committee something concrete to vote on — it doesn't matter how good your arguments are; if there isn't a concrete proposal for wording changes then the committee can't vote on it. In the end, the decision was that implicit move generation was a good thing, even though there was the potential for breaking existing code. However, the conditions under which move operations are implicitly generated have been tightened: the accepted proposal was N3203: Tightening the conditions for generating implicit moves by Jens Maurer, which provides wording for Bjarne's paper N3201: Moving Right Along. The proposal effectively treats copy, move and destruction as a group: if you specify any of them manually then the compiler won't generate any move operations, and if you specify a move operation then the compiler won't generate a copy. For consistency and safety, it would have been nice to prevent implicit generation of copy operations under the same circumstances, but for backwards compatibility this is still done when it would be done under C++03, though this is deprecated if the user specifies a destructor or only one of the copy operations.
Exceptions and Destructors
The second big issue from the
October mailing was the issue of implicitly adding
noexcept to destructors. In the end, the committee went
for Jens Maurer's paper N3204:
Deducing "noexcept" for destructors — destructors have the
same exception specification they would have if they were implicitly
generated, unless the user explicitly says otherwise. This will break
code, but not much — the fraction of code that intentionally
throws an exception from a destructor is small, and easily annotated
with noexcept(false) to fix it.
Concurrency-related papers
There are 9 concurrency-related papers in this mailing, which I've summarised below. 8 of them were adopted at this meeting, and are now in the new C++0x working draft.
- N3188 - Revision to N3113: Async Launch Policies (CH 36)
This paper is a revision of N3113 from the August mailing. It is a minor revision to the previous paper, which clarifies and simplifies the proposed wording.
It provides a clearer basis for implementors to supply additional launch policies for
std::async, or for the committee to do so in a later revision of the C++ standard, by making thestd::launchenum a bitmask type. It also drops thestd::launch::anyenumeration value, and renamesstd::launch::synctostd::launch::deferred, as this better describes what it means.The use of a bitmask allows new values to be added which are either distinct values, or combinations of the others. The default policy for
std::asyncis thusstd::launch::async|std::launch::deferred.- N3191: C++ Timeout Specification
This paper is a revision of N3128: C++ Timeout Specification from the August mailing. It is a minor revision to the previous paper, which clarifies and simplifies the proposed wording.
There are several functions in the threading portion of the library that allow timeouts, such as the
try_lock_forandtry_lock_untilmember functions of the timed mutex types, and thewait_forandwait_untilmember functions of the future types. This paper clarifies what it means to wait for a specified duration (with the xxx_forfunctions), and what it means to wait until a specified time point (with the xxx_untilfunctions). In particular, it clarifies what can be expected of the implementation if the clock is changed during a wait.This paper also proposes replacing the old
std::chrono::monotonic_clockwith a newstd::chrono::steady_clock. Whereas the only constraint on the monotonic clock was that it never went backwards, the steady clock cannot be adjusted, and always ticks at a uniform rate. This fulfils the original intent of the monotonic clock, but provides a clearer specification and name. It is also tied into the new wait specifications, since waiting for a duration requires a steady clock for use as a basis.- N3192: Managing C++ Associated Asynchronous State
This paper is a revision of N3129: Managing C++ Associated Asynchronous State from the August mailing. It is a minor revision to the previous paper, which clarifies and simplifies the proposed wording.
This paper tidies up the wording of the functions and classes related to the future types, and clarifies the management of the associated asynchronous state which is used to communicate e.g. between a
std::promiseand astd::futurethat will receive the result.- N3193: Adjusting C++ Atomics for C Compatibility
This paper is an update to N3164: Adjusting C++ Atomics for C Compatibility from the October mailing.
It drops the C compatibility header
<stdatomic.h>, and the macro_Atomic, and loosens the requirements on theatomic_xxxtypes — they may be base classes of the associatedatomic<T>specializations, or typedefs to them.- N3194: Clarifying C++ Futures
This paper is a revision ofN3170: Clarifying C++ Futures from the October mailing.
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:
-
futuregains ashare()member function for easy conversion to the correspondingshared_futuretype; - Accessing a
shared_futurefor whichvalid()isfalseis now encouraged to throw an exception though it remains undefined behaviour; atomic_futureis to be removed;packaged_tasknow has avalid()member function instead ofoperator boolfor consistency with the future types.
A few minor changes have also been made to the wording to make things clearer.
-
- N3196: Omnibus Memory Model and Atomics Paper
This paper is an update to N3125: Omnibus Memory Model and Atomics Paper from the August mailing.
This paper clarifies the wording surrounding the memory model and atomic operations.
- N3197: Lockable Requirements for C++0x
This paper is an update to N3130: Lockable Requirements for C++0x from the October mailing. This is a minor revision reflecting discussions at Batavia.
This paper splits out the requirements for general lockable types away from the specific requirements on the standard mutex types. This allows the lockable concepts to be used to specify the requirements on a type to be used the the
std::lock_guardandstd::unique_lockclass templates, as well as for the various overloads of the wait functions onstd::condition_variable_any, without imposing the precise behaviour ofstd::mutexon user-defined mutex types.- N3209: Progress guarantees for C++0x (US 3 and US 186)(revised)
This paper is a revision ofN3152: Progress guarantees for C++0x (US 3 and US 186) from the October mailing. It is a minor revision to the previous paper, which extends the proposed wording to cover
compare_exchange_weakas well astry_lock.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.
- N3230: Constexpr Library Additions: future
This paper has not yet been accepted by the committee. It adds constexpr to the default constructors of
futureandshared_future, so that they can be statically initialized.
Other adopted papers
Of course, the committee did more than just address implicit move, exceptions in destructors and concurrency. The full minutes are available as N3212 in the mailing. Here is a quick summary of some of the other changes made:
- Library functions that don't throw exceptions have been changed to
use
noexcept - The ratio arithmetic facilities have been changed to allow
libraries to try and give the correct result if the result is
representable, but the intermediate calculations may overflow
(e.g.
ratio_add<ratio<1,INTMAX_MAX>,ratio<1,INTMAX_MAX>>) (N3210) - New functions have been added to retrieve the current new handler, terminate handler or unexpected handler (N3189)
- Alignment control is now done with the
alignaskeyword, rather than an attribute (N3190) - Virtual function override control is now done with keywords
(including the first context sensitive keywords:
overrideamdfinal) rather than attributes (N3206)
For the remaining changes, see the full minutes.
FCD comment status
The count of unresolved FCD comments is dropping rapidly, and now stands at 75 (out of 564 total), of which only 56 have any technical content. See N3224: C++ FCD Comment Status from the mailing for the full list.
Your comments
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: C++0x, C++, standards, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
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:
-
futuregains ashare()member function for easy conversion to the correspondingshared_futuretype; - Accessing a
shared_futurefor whichvalid()isfalseis now required to throw an exception rather than be undefined behaviour; atomic_futureis 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: C++0x, C++, standards, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
August 2010 C++ Standards Committee Mailing
Wednesday, 08 September 2010
The August 2010 mailing for the C++ Standards Committee was published recently. This is the post-meeting mailing for the August 2010 committee meeting, and contains a new C++0x Working Draft. At the meeting in August, the committee discussed many of the National Body comments on the FCD, and this draft incorporates those changes that the committee approved of. As you can see from the FCD Comment Status document in this mailing, there were 301 technical comments and a further 215 editorial comments. Of these, 98 technical comments have been accepted as-is, 8 have been accepted with changes, and 63 have been rejected, leaving 132 technical comments that have still not been addressed one way or the other.
No significant changes have been accepted to the concurrency-related parts of the working draft, though there are quite a few editorial comments. However, there are several papers in this mailing that address the National Body comments in this area. These papers have by and large been drafted to represent the consensus of those members of the concurreny group in the LWG who were present at the meeting. I have summarised these papers below.
Concurrency-related papers
- N3113: Async Launch Policies (CH 36)
This paper provides a clearer basis for implementors to supply additional launch policies for
std::async, or for the committee to do so in a later revision of the C++ standard, by making thestd::launchenum a bitmask type. It also drops thestd::launch::anyenumeration value, and renamesstd::launch::synctostd::launch::deferred, as this better describes what it means.The use of a bitmask allows new values to be added which are either distinct values, or combinations of the others. The default policy for
std::asyncis thusstd::launch::async|std::launch::deferred.- N3125: Omnibus Memory Model and Atomics Paper
This paper addresses several National Body comments by updating the wording in the draft standard to better reflect the intent of the committee.
- N3128: C++ Timeout Specification
There are several functions in the threading portion of the library that allow timeouts, such as the
try_lock_forandtry_lock_untilmember functions of the timed mutex types, and thewait_forandwait_untilmember functions of the future types. This paper clarifies what it means to wait for a specified duration (with the xxx_forfunctions), and what it means to wait until a specified time point (with the xxx_untilfunctions). In particular, it clarifies what can be expected of the implementation if the clock is changed during a wait.This paper also proposes replacing the old
std::chrono::monotonic_clockwith a newstd::chrono::steady_clock. Whereas the only constraint on the monotonic clock was that it never went backwards, the steady clock cannot be adjusted, and always ticks at a uniform rate. This fulfils the original intent of the monotonic clock, but provides a clearer specification and name. It is also tied into the new wait specifications, since waiting for a duration requires a steady clock for use as a basis.- N3129: Managing C++ Associated Asynchronous State
This paper tidies up the wording of the functions and classes related to the future types, and clarifies the management of the associated asynchronous state which is used to communicate e.g. between a
std::promiseand astd::futurethat will receive the result.- N3130: Lockable requirements for C++0x
This paper splits out the requirements for general lockable types away from the specific requirements on the standard mutex types. This allows the lockable concepts to be used to specify the requirements on a type to be used the the
std::lock_guardandstd::unique_lockclass templates, as well as for the various overloads of the wait functions onstd::condition_variable_any, without imposing the precise behaviour ofstd::mutexon user-defined mutex types.- N3132: Mathematizing C++ Concurrency: The Post-Rapperswil Model
This paper provides a mathematical description for the C++0x memory model. A similar description was used to highlight some of the areas that are clarified by the omnibus memory model paper (N3125) described above.
- N3136: Coherence Requirements Detailed
This paper introduces some simple coherence requirements to the memory model wording to make it clear that the sequence of values read for a given variable must be consistent across threads. The existence of a single modification order for each variable is a key component of the memory model, and the wording introduced in this paper makes it clear that this is a core requirement.
- N3137: C and C++ Liaison: Compatibility for Atomics
The structure of the atomic types and operations in the FCD was carefully worked out in conjunction with the C standards committee to ensure that the C++0x atomic types were compatible with those being introduced in the upcoming C1x standard. Unfortunately, the C committee introduced a new incompatible syntax for atomic types into the C1x draft earlier this year because they believed it was a better match for the C language.
This paper attempts to address this new incompatibility by removing the
atomic_xxx types that were originally added for C compatibility, leaving just thestd::atomic<T>class template. Also, a new_Atomic(T)macro is introduced for compatibility with the new C1x_Atomickeyword.
Other papers
As already mentioned, this mailing contains a new C++0x Working Draft, along with the usual post-meeting stuff — editors notes for the changes in the new draft, new issues lists, minutes of the meeting, etc. It also contains a complete list of the National Body Comments on the FCD, and a few other papers addressing National Body comments.
If you have any opinions on the resolution of any NB comments not yet formally accepted or rejected, please add them to the comments for this post.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
Reference Wrappers Explained
Wednesday, 14 July 2010
The
upcoming C++0x
standard includes reference wrappers in the form of
the std::reference_wrapper<T> class template, and
the helper function templates std::ref()
and std::cref(). As I mentioned in my blog post
on Starting
Threads with Member Functions and Reference Arguments, these
wrappers can be used to pass references to objects across interfaces
that normally require copyable (or at least movable) objects
— in that blog post, std::ref was used for passing
references to objects over to the new thread, rather than copying the
objects. I was recently asked what the difference was
between std::ref and std::cref, and how they
worked, so I thought I'd elaborate.
Deducing the Referenced Type
std::ref is a function template, so automatically
deduces the type of the wrapped reference from the type of the
supplied argument. This type deduction includes
the const-ness of the supplied object:
int x=3; const int y=4; std::reference_wrapper<int> rx=std::ref(x); // std::reference_wrapper<int> ry=std::ref(y); // error std::reference_wrapper<const int> rcy=std::ref(y);
On the other hand, though std::cref also deduces the
type of the wrapped reference from the supplied argument,
it always wraps a const reference:
int x=3; const int y=4; // std::reference_wrapper<int> rx=std::cref(x); // error std::reference_wrapper<const int> rcx=std::cref(x); // std::reference_wrapper<int> ry=std::cref(y); // error std::reference_wrapper<const int> rcy=std::cref(y);
Since a no-const-reference can always be bound to
a const reference, you can thus
use std::ref in pretty much every case where you would
use std::cref, and your code would work the same. Which
begs the question: why would you ever choose to
use std::cref?
Using std::cref to prevent modification
The primary reason for choosing std::cref is because
you want to guarantee that the source object is not modified through
that reference. This can be important when writing multithreaded
code — if a thread should not be modifying some data then it
can be worth enforcing this by passing a const
reference rather than a mutable reference.
void foo(int&); // mutable reference int x=42; // Should not be modified by thread std::thread t(foo,std::cref(x)); // will fail to compile
This can be important where there are overloads of a function such
that one takes a const reference, and the other a
non-const reference: if we don't want the object
modified then it is important that the overload taking
a const reference is chosen.
struct Foo
{
void operator()(int&) const;
void operator()(int const&) const;
};
int x=42;
std::thread(Foo(),std::cref(x)); // force const int& overload
References to temporaries
std::cref has another property missing
from std::ref — it can bind to temporaries, since
temporary objects can bind to const references. I'm
not sure this is a good thing, especially when dealing with multiple
threads, as the referenced temporary is likely to have been
destroyed before the thread has even started. This is therefore
something to watch out for:
void bar(int const&); std::thread t(bar,std::cref(42)); // oops, ref to temporary
Documentation
Finally, std::cref serves a documentation purpose,
even where std::ref would suffice — it declares
in big bold letters that this reference cannot be used to modify the
referenced object, which thus makes it easier to reason about the
code.
Recommendation
I would recommend that you use std::cref in preference
to std::ref whenever you can — the benefits as
documentation of intent, and avoiding accidental modification
through the reference make it a clear winner in my opinion. Of
course, if you do want to modify the referenced
object, then you need to use std::ref, but such usage
now stands out, and makes it clear that this is the intent.
You do still need to be careful to ensure that you don't try and
wrap references to temporaries, particularly when
applying std::cref to the result of a function call,
but such uses should stand out — I expect most uses to be
wrapping a reference to a named variable rather than wrapping a
function result.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: reference wrappers, ref, cref, cplusplus
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
Last day for comments on the C++0x FCD
Thursday, 17 June 2010
The BSI deadline for comments on the C++0x FCD is tomorrow, Friday 18th June 2010. The ISO deadline is 26th July 2010, but we have to write up comments for submission in the form required for ISO, which takes time.
If you have a comment on the FCD, please see my earlier blog post for how to submit it to BSI. Help us make the C++0x standard as good as it can be.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, C++0x, WG21, FCD
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
March 2010 C++ Standards Committee Mailing
Thursday, 08 April 2010
The March 2010 mailing for the C++ Standards Committee was published last week. This is the post-meeting mailing for the March 2010 committee meeting, and contains the C++0x Final Committee Draft, which I blogged about last week.
There are 6 concurrency-related papers (of which my name is on two), which I summarize below:
Concurrency-related papers
- N3057: Explicit Initializers for Atomics
This paper proposes new initializers for atomic variables, providing a means of writing code which can be compiled as either C or C++. e.g.
void foo() { atomic_int a=ATOMIC_VAR_INIT(42); // initialize a with 42 atomic_uint b; // uninitialized atomic_init(&b,123); // b now initialized to 123 }- N3058: Futures and Async Cleanup (Rev.)
This is a revision of N3041 to resolve many of the outstanding issues with futures and async. Mostly it's just wordsmithing to tidy up the specification, but there's a few key changes:
- Defined behaviour for
the
wait_for()andwait_until()member functions ofstd::future,std::shared_futureandstd::atomic_futurewhen used withstd::asyncand a launch policy ofstd::launch::sync. The return value is now a value of the newstd::future_statusenumeration, and can bestd::future_status::readyif the future becomes ready before the timeout,std::future_status::timeoutif the wait times out, orstd::future_status::deferredif the future comes from a call tostd::asyncwith a launch policy ofstd::launch::syncand the function associated with the future hasn't yet started execution on any thread. - The wording
for
std::asyncadopts the same wording asstd::threadto clarify the copy/move and perfect forwarding semantics of the call.
- Defined behaviour for
the
- N3069: Various threads issues in the library (LWG 1151)
This is a revision of N3040, and highlights which operations through iterators constitute accesses and data races, and explicitly allows for synchronization by writing and reading to/from a stream.
- N3070:
Handling Detached Threads and
thread_localVariables This is a hugely simplified replacement for my previous paper N3038. Rather than creating contexts for
thread_localvariables, this paper proposes new member functions forstd::promiseandstd::packaged_taskto allow the value to be set at the point of call, but threads waiting on associated futures to be woken only afterthread_localvariables have been destroyed at thread exit. This means that you can now safely wait on a future which is set in such a fashion when waiting for a task running on a background thread to complete, without having to join with the thread or worry about races arising from the destructors ofthread_localvariables. The paper also adds a similar mechanism for condition variables as a non-member function.- N3071:
Renaming
launch::anyand what asyncs really might be (Rev.) This is a revision of N3042 proposing renaming
std::launch::anytostd::launch::sync_or_async. This paper was not approved.- N3074: Updates to C++ Memory Model Based on Formalization
This is a revision of N3045. This paper proposes some changes to the wording of the memory model in order to ensure that it means what we intended it to mean.
Other Papers
There's several non-concurrency papers in the mailing as well as the standard set (working draft, agenda, issues lists, etc.). The most significant of these in my view are the following 3 papers. Check the mailing for the full set.
- N3050: Allowing Move Constructors to Throw (Rev. 1)
This paper adds the new
noexceptkeyword to C++. This is used in place of an exception specification. On its own it means that the function does not throw any exceptions, but it can also be used with a boolean constant expression wheretruemeans that the function doesn't throw, andfalsemeans that it might. e.g.void foo() noexcept; // will not throw void bar() noexcept(true); // will not throw void baz() noexcept(false); // may throw
If a
noexceptexception specification is violated thenstd::terminate()is called.The primary benefit from the boolean-constant-expression version is in templates, where the boolean expression can check various properties of the template parameter types. One of the things you can check is whether or not particular operations throw, e.g. by using the new
has_nothrow_move_constructortype trait to declare the move constructor for a class to benoexceptif its class members have non-throwing move constructors:template<typename T> class X { T data; public: X(X&& other) noexcept(std::has_nothrow_move_constructor<T>::value): data(std::move(other.data)) {} };- N3053: Defining Move Special Member Functions
This proposal ensures that user-defined classes have move constructors and move assignment operators generated for them by the compiler if that is safe. Explicitly declaring a copy or move constructor will prevent the implicit declaration of the other, and likewise for copy and move assignment. You can always request the default definition using the
= defaultsyntax.This means that lots of user code will now be able to readily take advantage of move semantics with a simple code change or even just a recompile. This can potentially be of major performance benefit.
- N3055: A Taxonomy of Expression Value Categories
This paper nails down the true distinctions between lvalues, rvalues and rvalue references. It provides a new set of names to identify the distinct categories of values in C++ — lvalues and rvalues we already have, but now there's xvalues, prvalues and glvalues too. This categorization allows for better specification of when things can bind to lvalue references or rvalue references, when the compiler can eliminate copies or moves.
Please comment on the FCD
The purpose of the C++0x Final Committee Draft is to get comments prior to publication to ensure the final C++0x standard is as defect free as possible. This opportunity is only available for a limited time, so please comment on the FCD.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
C++0x Final Committee Draft Published - Please Comment
Friday, 02 April 2010
Earlier this week, the Final Committee Draft (FCD) of the C++0x standard was published. This means that C++0x is now in the final stages of bug fixing and wordsmithing before publication. If all goes to plan, the draft will move to Final Draft International Standard (FDIS) early in 2011, and will be a new standard by the end of 2011.
The publication of the FCD means that the draft standard has now been officially put up for review by the national standards bodies of ISO's member countries. The British Standards Institution is one of several national bodies that is actively involved in the standardisation of the C++ language. The panel members of the C++ Committee of the BSI, IST 5/-/21, are currently compiling a list of comments on the FCD. We intend to submit these as the BSI's National Body comments, aimed at getting issues with the FCD addressed before it becomes the new international standard for C++.
We're welcoming additional comments, and would like to provide a channel for anyone who may be interested in the C++0x Standard, but not able to be fully involved in the standards process, to submit comments. Note that not all comments — regardless of whether they are submitted by panel members or non-members — will go forward.
Here is some guidance on what we are looking for:
- Suggestions for how to improve the clarity of the wording, even if that's just by adding a cross-reference to a relevant paragraph elsewhere;
- Comments that identify any under/over specification; and
- Comments highlighting inconsistencies or contradictions in the draft text.
Comments should be specific and preferably should include suggested updated wording (and if you need help formulating updated wording we can provide it, within reason) — the C++ standards committee is working to a very tight schedule in order to get C++0x out as soon as possible, and comments without wording (which therefore require more work from the committee) are more likely to be rejected.
The time for adding/removing features has now passed, so comments should focus on improving the draft as it stands rather than suggesting new features.
Owing to the time scale for submission to BSI and ISO, comments need to be submitted by Friday 18th June 2010.
If you have any comments, feel free to post them in the comment section of this blog entry, or email them to me. I will forward all appropriate suggestions to the rest of the BSI panel (whether or not I agree with them).
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, C++0x, WG21, FCD
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
February 2010 C++ Standards Committee Mailing
Tuesday, 23 February 2010
The February 2010 mailing for the C++ Standards Committee was published last week. This is the pre-meeting mailing for the March 2010 committee meeting and contains a new working draft.
There are 5 concurrency-related papers (of which my name is on one), which I summarize below:
Concurrency-related papers
- N3038:
Managing the lifetime of
thread_localvariables with contexts (Revision 2) This is my paper on creating contexts for
thread_localvariables. The use of such contexts allows you to control when variables that are declared asthread_localare destroyed. It is a revision of my previous paper N2959; the primary change is that contexts can now be nested, which allows library code to use them without having to know whether or not a context is currently active.- N3040: Various threads issues in the library (LWG 1151)
This paper by Hans Boehm seeks to address LWG issue 1151. The key issue is to ensure that it is clear which operations may constitute a data race if they run concurrently without synchronization.
- N3041: Futures and Async Cleanup
The adoption of multiple papers affecting futures and
std::asyncat the same C++ committee meeting meant that the wording ended up being unclear. Detlef Vollmann kindly volunteered to write a paper to resolve these issues, and this is it.Unfortunately, I think that some of the wording is still unclear. I also dislike Detlef's proposal to force the
wait_forandwait_untilmember functions of the future types to throw exceptions if the future was created from a call tostd::asyncwith a launch policy ofstd::launch::sync. My preferred alternative is to change the return type fromboolto an enumeration with distinct values for if the future is ready, if the wait timed out, or if the future holds a deferred function fromstd::launch::syncthat has not yet started. This would be similar to the current behaviour ofstd::condition_variable::wait_forandstd::condition_variable::wait_until, which return astd::cv_statusenumeration value.- N3042:
Renaming
launch::anyand what asyncs really might be This is another paper from Detlef Vollmann proposing renaming
std::launch::anytostd::launch::any_sync. His rationale is that future revisions of the C++ standard may wish to add values to thestd::launchenumeration for additional types of async calls that should not be covered bystd::launch::any. Personally, I think this is a non-issue, and should be covered as and when such values are added.- N3045: Updates to C++ Memory Model Based on Formalization
Following attempts to create a mathematical formalization of the memory model it became clear that some cases were unclear or ambiguous or did not guarantee the desired semantics. This paper proposes some changes to the wording of the memory model in order to ensure that it means what we intended it to mean.
Other Papers
There's several non-concurrency papers in the mailing as well as the standard set (working draft, agenda, issues lists, etc.). The most significant of these in my view is N3044 which proposes compiler-defined move constructors and assignment operators. Check the mailing for the full set.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
The difference between struct and class in C++
Sunday, 21 February 2010
I've seen a lot of people asking about the differences
between the use of the struct and class
keywords in C++ lately. I don't know whether there's an influx of
C++ programmers due to the upcoming C++0x standard, or whether I've
just noticed people asking questions that haven't caught my eye
before. Whatever the reason, I'm writing this blog entry as
something I can point to the next time someone asks the
question.
Declaring and defining user-defined types
The primary use of both the struct
and class keywords is to define a user-defined type. In
C++, such a user-defined type is termed a "class" regardless of
which keyword is used in the definition. The choice of keyword is in
one sense arbitrary, since the same features and facilities are
available whichever keyword is used — there is only one
semantic difference which we shall look at shortly. The following
two class definitions are thus equivalent in all respects apart from
the names of the classes:
struct type_a
{
private:
int data;
public:
type_a(int data_):
data(data_)
{}
virtual void foo()=0;
virtual ~type_a()
{}
};
class type_b
{
private:
int data;
public:
type_b(int data_):
data(data_)
{}
virtual void foo()=0;
virtual ~type_b()
{}
};
As this little example shows, you can have constructors,
destructors, member functions, private members and even virtual
member functions in a class declared with the struct
keyword, just as you can with a class declared using
the class keyword. Though this example doesn't show it,
you can also use the struct keyword to declare classes
with base classes.
You can even forward-declare your class using one keyword and then define it with the other, though compilers have been known to complain about this usage:
struct foo;
class foo {};
class bar;
struct bar {};
So, what of the minor semantic difference then? The change is in
the default access specifier for members and base
classes. Though classes defined using either keyword can
have public, private
and protected base classes and members, the default
choice for classes defined using class
is private, whilst for those defined
using struct the default is public. This
is primarily for backwards compatibility with C: the members of a C
structure can be freely accessed by all code so in order to allow
existing C code to compile unchanged as C++ the default access
specifier for members of a class declared with struct
must be public. On the other hand, private data is a
key aspect of the encapsulation aspect of object-oriented design, so
this is the default for those classes declare
with class.
C doesn't have inheritance, but the default access specifier for
base classes varies with the keyword used to declare the derived
class too. It is public for classes declared
with struct and private for those declared
with class just the same as for data members. You can
still override it with an explicit specifier in both cases.
Let's take a quick look at some examples to see how that works:
struct s1
{
int a; // public
private:
int b; // private
protected:
int c; // protected
public:
int d; // public again
};
class c1
{
int a; // private
private:
int b; // still private
protected:
int c; // protected
public:
int d; // public
};
struct s2:
s1, // public
private c1, // private
type_b, // public again
protected foo, // protected
public bar // public again
{};
class c2:
s1, // private
private c1, // still private
type_b, // private again
protected foo, // protected
public bar // public
{};
As far as declaring and defining user-defined types in C++, that is
the only difference; in all other respects, classes declared
with struct are identical to those declared
with class.
C Compatibility
We touched on this a bit earlier: classes declared with
the struct keyword can be compiled as C if they don't
use any features that are C++ specific. Thus the following is both a
valid C++ class and a valid C structure:
struct c_compatible
{
int i;
char c;
double d;
};
It is therefore common to see struct used in header
files that are shared between C and C++. Since non-virtual member
functions don't affect the class layout you can even have member
functions in such a type, provided they are hidden from the C
compiler with a suitable #ifdef:
struct baz
{
int i;
#ifdef __cplusplus
void foo();
#endif;
};
Templates
There is one place where you can use the class keyword
but not the struct one, and that is in the declaration
of a template. Template type parameters must be declared using
either the class or typename
keyword; struct is not allowed. The choice
of class or typename in this case is again
arbitrary — the semantics are identical. The choice of keyword
does not impose any semantic meaning, any type (whether a built in
type like int or a user-defined type like a class or
enumeration) can be used when instantiating the template in either
case.You can of course declare a class template with
the struct keyword, in which case the default access
for the members of the template is public.
template<class T> // OK
void f1(T t);
template<typename T> // OK
void f2(T t);
template<struct T> // ERROR, struct not allowed here
void f3(T t);
template<class T>
struct S
{
T x; // public member
};
That's all folks!
These are the only concrete distinctions between the uses of
the struct keyword and the class keyword
in C++. People also use them for documentation purposes,
reserving struct for C-compatible classes, or classes
with no member functions, or classes with no private data, or
whatever their coding standard says. However, this is just
documentation and convention rather than an inherent difference: you
could use struct for all your classes,
or class for all your classes except those that are
shared with C.
Posted by Anthony Williams
[/ cplusplus /] permanent link
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
