Just Software Solutions

Blog Archive for / cplusplus /

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

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 the std::launch enum a bitmask type. It also drops the std::launch::any enumeration value, and renames std::launch::sync to std::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::async is thus std::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_for and try_lock_until member functions of the timed mutex types, and the wait_for and wait_until member functions of the future types. This paper clarifies what it means to wait for a specified duration (with the xxx_for functions), and what it means to wait until a specified time point (with the xxx_until functions). 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_clock with a new std::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::promise and a std::future that 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_guard and std::unique_lock class templates, as well as for the various overloads of the wait functions on std::condition_variable_any, without imposing the precise behaviour of std::mutex on 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 the std::atomic<T> class template. Also, a new _Atomic(T) macro is introduced for compatibility with the new C1x _Atomic keyword.

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: , , ,
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 left.

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: , , ,
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 left.

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: , , ,
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 left.

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() and wait_until() member functions of std::future, std::shared_future and std::atomic_future when used with std::async and a launch policy of std::launch::sync. The return value is now a value of the new std::future_status enumeration, and can be std::future_status::ready if the future becomes ready before the timeout, std::future_status::timeout if the wait times out, or std::future_status::deferred if the future comes from a call to std::async with a launch policy of std::launch::sync and the function associated with the future hasn't yet started execution on any thread.
  • The wording for std::async adopts the same wording as std::thread to clarify the copy/move and perfect forwarding semantics of the call.
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_local Variables

This is a hugely simplified replacement for my previous paper N3038. Rather than creating contexts for thread_local variables, this paper proposes new member functions for std::promise and std::packaged_task to allow the value to be set at the point of call, but threads waiting on associated futures to be woken only after thread_local variables 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 of thread_local variables. The paper also adds a similar mechanism for condition variables as a non-member function.

N3071: Renaming launch::any and what asyncs really might be (Rev.)

This is a revision of N3042 proposing renaming std::launch::any to std::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 noexcept keyword 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 where true means that the function doesn't throw, and false means 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 noexcept exception specification is violated then std::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_constructor type trait to declare the move constructor for a class to be noexcept if 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 = default syntax.

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: , , ,
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 left.

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: , , ,
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 left.

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_local variables with contexts (Revision 2)

This is my paper on creating contexts for thread_local variables. The use of such contexts allows you to control when variables that are declared as thread_local are 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::async at 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_for and wait_until member functions of the future types to throw exceptions if the future was created from a call to std::async with a launch policy of std::launch::sync. My preferred alternative is to change the return type from bool to an enumeration with distinct values for if the future is ready, if the wait timed out, or if the future holds a deferred function from std::launch::sync that has not yet started. This would be similar to the current behaviour of std::condition_variable::wait_for and std::condition_variable::wait_until, which return a std::cv_status enumeration value.

N3042: Renaming launch::any and what asyncs really might be

This is another paper from Detlef Vollmann proposing renaming std::launch::any to std::launch::any_sync. His rationale is that future revisions of the C++ standard may wish to add values to the std::launch enumeration for additional types of async calls that should not be covered by std::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: , , ,
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 left.

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! 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 left.

November 2009 C++ Standards Committee Mailing

Tuesday, 17 November 2009

The November 2009 mailing for the C++ Standards Committee was published last week. This is the post-meeting mailing for the October committee meeting and contains a new working draft incorporating all the proposals accepted at the October meeting.

As those of you who read Herb Sutter's blog or Michael Wong's blog will already know, the big news for concurrency is that a proposal for std::async has been accepted, and this is reflected in the latest working draft.

There are 5 concurrency-related papers (of which my name is on one), which I summarize below:

Concurrency-related papers

N2985: C and C++ Thread Compatibility

Lawrence Crowl has been through the concurrency and multithreading support from the C++ working draft, and compared this to that now being added to the C working draft for the next C standard. This paper contains his observations and recommendations about the potential for compatibility between the types and functions provided by the two draft standards. I agree with some of his recommendations, and disagree with others. No action will be taken by the C++ committee unless his recommendations become full proposals.

N2992: More Collected Issues with Atomics

This is Lawrence Crowl's paper which rounds up various issues with the C++ atomics. It was accepted by the committee, and has been incorporated into the working draft. The most noticeable change is that the atomic types and functions now live in the <atomic> header. The macro for identifying lock-free atomics has been expanded into a set of macros, one per type, and a guarantee has been added that all instances of a type are lock-free, or all are not lock-free (rather than it being allowed to vary between objects). There is also a clarification that if you use compare-exchange operations on a type with padding bits then the padding bits will be part of the comparison (which will therefore affect atomic<float> or similar), plus a few other clarifications.

N2996: A Simple Asynchronous Call

This paper is by Herb Sutter and Lawrence Crowl, and brings together their papers from the pre-meeting mailing (N2970 and N2973) based on feedback from the committee. This is the std::async proposal that got accepted, and which has been incorporated into the working draft.

The result is that we have a variadic async function with an optional launch policy as the first argument, which specifies whether the function is to be spawned on a separate thread, deferred until get() or wait() is called on the returned future, or either, at the choice of the implementation.

N2997: Issues on Futures (Rev. 1)

This is a revision of N2967 from the pre-meeting mailing, which incorporates feedback from the committee. This is the version that was accepted, and which has been incorporated into the working draft. The key change is that unique_future has been renamed to just future in order to make things easier to read in what is anticipated to be the common case.

N2999: Background for issue 887: Clocks and Condition Variables (Rev. 1)

This is a minor revision of Detlef's paper from the pre-meeting mailing (N2969). The changes it proposes have not yet been accepted into the working paper, and will make it implementation-dependent which clocks can be used for condition variable waits.

Other concurrency changes in the working draft

  • std::mutex now has a constexpr constructor, so namespace-scope objects are guaranteed to be safe from initialization order issues.
  • The return type of the wait_for and wait_until member functions of std::condition_variable and std::condition_variable_any has been changed from a bool to a cv_status enum. This makes it clear whether the return is due to a signal (or spurious wake) or because the operation timed out.

Updated implementation

Our just::thread implementation of the C++0x thread library will shortly be updated to incorporate all these changes (including an implementation of std::async). Existing customers will get a free upgrade as usual.

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

September 2009 C++ Standards Committee Mailing

Wednesday, 30 September 2009

The September 2009 mailing for the C++ Standards Committee was published today. This is the pre-meeting mailing for the October committee meeting and contains the first new working draft since the "Concepts" feature was voted out of C++0x in July.

There is also quite a large number of papers in this mailing, including 7 concurrency-related papers (of which my name is on 2), which I summarize below:

Concurrency-related papers

N2955: Comments on the C++ Memory Model Following a Partial Formalization Attempt

Mark has been working on a formal model for parts of the C++ memory model, and has identified a few cases where the wording could be improved to clarify things.

N2959: Managing the lifetime of thread_local variables with contexts (Revision 1)

This is a revision of my earlier paper, N2907 which expands my proposal for a thread_local_context class, along with full proposed wording. I think this provides a workable solution to the general problem of ensuring that destructors for thread_local variables are run at particular points in the execution of a program as discussed in N2880.

N2967: Issues on Futures

This paper that I co-authored with Detlef Vollmann provides a complete rewording for the "Futures" section of the standard (30.6). It folds the proposed changes from N2888 in with changes requested by the LWG at July's meeting (including the addition of a new future type — atomic_future which serializes all operations), and editorial comments on the earlier wording. It doesn't resolve everything — there is still some discussion over whether unique_future::get() should return a value or a reference, for example — but it provides a sound basis for further discussion.

N2969: Background for issue 887: Clocks and Condition Variables

Detlef argues the case that std::condition_variable::wait_for and std::condition_variable::wait_until may wake "too late" if the user adjusts the system clock during a wait, and suggests simplifying the overload set to match the minimum requirements of POSIX. LWG has already decided that this is Not A Defect (NAD), and I agree — there are no guarantees about how soon after the specified timeout the wait will return, and this is thus entirely a quality of implementation issue.

N2970: A simple async() (revision 1)

This is a revision to Herb Sutter's take on a std::async function. There is a lot of discussion around the various issues, but the proposed wording seems incomplete — for example, if the unique_future associated with a synchronous async call is moved into a shared_future which is then copied, which call to get() runs the task?

N2973: An Asynchronous Call for C++

This is a revision to Lawrence Crowl's take on a std::async function. Whilst better specified than N2970 (a "serial" task is invoked in unique_future::get() or when the unique_future is moved into a shared_future), I'm not entirely happy with the result.

N2974: An Analysis of Async and Futures

To aid the committee with deciding on the semantics of std::async, Lawrence has put together this paper which outlines various options for creating futures from an async function. He then goes on to outline the operations that we may wish to perform on those futures, and how they relate to the various options for async.

As you can see by the 3 papers on the issue, std::async is a hot topic. I hope that a single coherent design can be agreed on at Santa Cruz, and incorporated into the standard. Comment on this blog post if you've got an opinion on the matter, and I'll pass it on.

Other papers

As I said at the beginning of this post, there are quite a few papers in this mailing. Other than the new working draft, there were 3 papers that piqued my interest:

Other papers include changes to the allocator proposals, papers to cover specific core issues, a couple of papers on type traits and a couple on pairs and tuples. See the full paper list for further details.

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

More recent entries Older entries

Design and Content Copyright © 2005-2024 Just Software Solutions Ltd. All rights reserved. | Privacy Policy