Faq C++ Isocpp
Faq C++ Isocpp
Templates
Container Classes
Class Libraries
Exceptions and Error Handling
Reference and Value Semantics
Inline Functions
Pointers to Member Functions
Serialization and Unserialization
C++11
C++11 Overview
C++11 Language Extensions — General Features
C++11 Language Extensions — Classes
C++11 Language Extensions — Other Types
C++11 Language Extensions — Templates
C++11 Language Extensions — Concurrency
C++11 Language Extensions — Miscellaneous Language Features
C++11 Library Extensions — General Libraries
C++11 Library Extensions — Containers and Algorithms
C++11 Library Extensions — Concurrency
C++14
C++14 Overview
C++14 Language Extensions
C++14 Library Extensions
Miscellaneous Q&A
Compiler Dependencies
Miscellaneous Technical Issues
Miscellaneous Environmental Issues
Miscellaneous Style Issues
C++0x Concepts — Historical FAQs
Myths and Urban Legends About C++
Partial List of ISO C++ Committee Members
What is C++?
Is C++ a practical language?
Is C++ a perfect language?
What is the zero-overhead principle?
What’s so great about classes?
What’s the big deal with OO?
What’s the big deal with generic programming?
What is multiparadigm programming?
Is C++ better than Java? (or C#, C, Objective-C, JavaScript, Ruby, Perl, PHP, Haskell,
FORTRAN, Pascal, Ada, Smalltalk, or any other language?)
Why is C++ so big?
Who uses C++?
How long does it take to learn C++?
What’s the best way to improve my C++ programs?
Does it matter which programming language I use?
What are some features of C++ from a business perspective?
Are virtual functions (dynamic binding) central to OO/C++?
I’m from Missouri. Can you give me a simple reason why virtual functions (dynamic
binding, dynamic polymorphism) and templates (static polymorphism) make a big difference?
Is C++ backward compatible with ANSI/ISO C?
Why is C++ (almost) compatible with C?
When was C++ invented?
Why was C++ invented?
Where did the name C++ come from?
Why does C++ allow unsafe code?
Why are some things left undefined in C++?
Why is portability considered so important?
Is C++ standardized?
Who is on the standardization committee?
Where can I get a copy of the C++ standard?
What is the difference between C++98 and C++03?
What is the difference between C++98 and C++0x?
What is the difference between C++98 and C++11?
What is the difference between C++11 and C++14?
What are some “interview questions” I could ask that would let me know if candidates really
know their stuff?
What does the FAQ mean by “such and such is evil”?
Will I sometimes use any so-called “evil” constructs?
Is it important to know the technical definition of “good OO”? Of “good class design”?
What should I tell people who complain that the word “FAQ” is misleading, that it
emphasizes the questions rather than the answers, and that we should all start using a different
acronym?
How can I help make the C++ FAQ even better??!??
What is C++?
C++ is a general-purpose programming language with a bias towards systems programming that
is a better C
supports data abstraction (e.g., classes)
supports object-oriented programming (e.g., inheritance)
supports generic programming (e.g., reusable generic containers and algorithms)
supports functional programming (e.g., template metaprogramming, lambda
functions, constexpr)
It is defined by an ISO standard, offers stability over decades, and has a large and lively user
community. See also The C++ Programming Language and Evolving a language in and for the real
world: C++ 1991-2006.
See also when and why C++ was invented.
Is C++ a practical language?
Yes.
C++ is a practical tool. It’s not perfect, but it’s useful.
In the world of industrial software, C++ is viewed as a solid, mature, mainstream tool. It has
widespread industry support which makes it “good” from an overall business perspective.
Is C++ a perfect language?
Nope.
C++ wasn’t designed to demonstrate what a perfect language looks like. It was designed to be a
practical tool for solving real world problems. It has a few warts, as do all practical programming
tools, but the only place where it’s appropriate to keep fiddling with something until it’s perfect is in
a pure academic setting. That wasn’t C++’s goal.
Is C++ standardized?
Yes.
The C++ standard was finalized and adopted by ISO (International Organization for
Standardization) as well as several national standards organizations such as INCITS (the U.S.
National Committee for Information Technology Standards), BSI (the British Standards Institute),
DIN (the German national standards organization). The ISO standard was finalized and adopted by
unanimous vote in November 1997, with minor updates in 2003 and now significant and valuable
updates in 2011. Another set of updates is expected to be published in 2014.
The U.S. C++ committee is called “PL22.16”. The ISO C++ standards group is called “WG21”. The
major players in the C++ standards process have included just about everyone: representatives from
Australia, Canada, Denmark, Finland, France, Germany, Ireland, Japan, the Netherlands, New
Zealand, Sweden, the UK, and the USA, along with representatives from about a hundred
companies and many interested individuals. Major players have included AT&T, Ericsson, Digital,
Borland, Hewlett Packard, IBM, Intel, Mentor Graphics, Microsoft, NVidia, Silicon Graphics, Sun
Microsystems, and Siemens.
For further information see the ISO C++ standardization pages, including but not limited to
the committee page
the meetings and participation page
the ISO/IEC JTC1 procedures summary
Who is on the standardization committee?
See also the committee page.
The committee consists of a large number of people (about 200) out of whom about 100 turn up at
the week-long meetings two or three times a year. In addition there are national standards groups
and meetings in several countries. Most members contribute either by attending meetings, by taking
part in email discussions, or by submitting papers for committee consideration. Most members have
friends and colleagues who help them. From day #1, the committee has had members from many
countries and at every meeting people from half a dozen to a dozen countries attend. The final votes
are done by about 20 national standards bodies. Thus, the ISO C++ standardization is a fairly
massive effort, not a small coherent group of people working to create a perfect language for
“people just like themselves.” The standard is what this group of volunteers can agree on as being
the best they can produce that all can live with.
Naturally, many (but not all) of these volunteers have day jobs focused on C++: They include
compiler writers, tool builders, library writers, application builders, researchers, book authors,
consultants, test-suite builders, and more.
Here is a very-partial list of some major organizations involved: Adobe, Apple, Boost, Bloomberg,
EDG, Google, HP, IBM, Intel, Microsoft, Oracle, Red Hat.
Here is a short list of names of members who you may have encountered in the literature or on the
web: Dave Abrahams, Matt Austern, Pete Becker, Hans Boehm, Steve Clamage, Lawrence Crowl,
Beman Dawes, Francis Glassborow, Doug Gregor, Pablo Halpern, Howard Hinnant, Jaakko Jarvi,
John Lakos, Alisdair Meredith, Jens Maurer, Jason Merrill, Sean Parent, P.J. Plauger, Tom Plum,
Gabriel Dos Reis, Bjarne Stroustrup, Herb Sutter, David Vandevoorde, Michael Wong. Apologies
to the 200+ current and past members that we couldn’t list. Also, please note the author lists on the
various papers: a standard is written by (many) individuals, not by an anonymous committee.
You can get a better impression of the breath and depth of expertise involved by examining the
authors listed in the WG21 papers archive, but please remember there are major contributors to the
standards effort who do not write a lot.
Where can I get a copy of the C++ standard?
See isocpp.org’s The Standard page.
What is the difference between C++98 and C++03?
From a programmer’s view there is none. The C++03 revision of the standard was a bug fix release
for implementers to ensure greater consistency and portability. In particular, tutorial and reference
material describing C++98 and C++03 can be used interchangeably by all except compiler writers
and standards gurus.
Learning C++
Save to:
InstapaperPocketReadability
Contents of this section:
What is mentoring?
Should I learn C before I learn C++?
Should I learn Objective-C or another OO language before I learn C++?
How do I start learning C++?
What is the best book to learn C++ from?
Should I buy one book, or several?
What are some best-of-breed C++ morality guides?
What are some best-of-breed C++ legality guides?
What are some best-of-breed C++ programming-by-example guides?
Are there other books that are relevant to C++?
Will someone here help me with my homework?
Where can I get a free C++ compiler?
What is mentoring?
It’s the most important tool in learning a new technology.
Object-oriented and generic thinking is caught, not just taught. Get cozy with someone
who really knows what they’re talking about, and try to get inside their head and watch them solve
problems. Listen. Learn by emulating.
If you’re working for a company, get them to bring someone in who can act as a mentor and guide.
We’ve seen gobs and gobs of money wasted by companies who “saved money” by simply buying
their employees a book (“Here’s a book; read it over the weekend; on Monday you’ll be an
OO/generic developer”).
Coding Standards
Save to:
InstapaperPocketReadability
Contents of this section:
Const Correctness
Save to:
InstapaperPocketReadability
Contents of this section:
References
Save to:
InstapaperPocketReadability
Contents of this section:
What is a reference?
What happens if you assign to a reference?
What happens if you return a reference?
What does object.method1().method2() mean?
How can you reseat a reference to make it refer to a different object?
Why does C++ have both pointers and references?
When should I use references, and when should I use pointers?
What does it mean that a reference must refer to an object, not a dereferenced null pointer?
What is a handle to an object? Is it a pointer? Is it a reference? Is it a pointer-to-a-pointer?
What is it?
Should I use call-by-value or call-by-reference?
Why is this not a reference?
What is a reference?
An alias (an alternate name) for an object.
Remember: the reference is the referent, so changing the reference changes the state of the referent.
In compiler writer lingo, a reference is an “lvalue” (something that can appear on the left hand side
of an assignment operator).
Unlike a pointer, once a reference is bound to an object, it can not be “reseated” to another object.
The reference isn’t a separate object. It has no identity. Taking the address of a reference gives you
the address of the referent. Remember: the reference is its referent.
In that sense, a reference is similar to a const pointer such as int* const p (as opposed to
a pointer to const such as const int* p). But please don’t confuse references with pointers;
they’re very different from the programmer’s standpoint.
References are usually preferred over pointers whenever you don’t need “reseating”. This usually
means that references are most useful in a class’s public interface. References typically appear on
the skin of an object, and pointers on the inside.
The exception to the above is where a function’s parameter or return value needs a “sentinel”
reference — a reference that does not refer to an object. This is usually best done by
returning/taking a pointer, and giving the nullptr value this special significance (references must
always alias objects, not a dereferenced null pointer).
Note: Old line C programmers sometimes don’t like references since they provide reference
semantics that isn’t explicit in the caller’s code. After some C++ experience, however, one quickly
realizes this is a form of information hiding, which is an asset rather than a liability. E.g.,
programmers should write code in the language of the problem rather than the language of the
machine.
1. T* p = nullptr;
2. T& r = *p; // illegal
NOTE: Please do not email us saying the above works on your particular version of your particular
compiler. It’s still illegal. The C++ language, as defined by the C++ standard, says it’s illegal; that
makes it illegal. The C++ standard does not require a diagnostic for this particular error, which
means your particular compiler is not obliged to notice that p is nullptr or to give an error
message, but it’s still illegal. The C++ language also does not require the compiler to generate code
that would blow up at runtime. In fact, your particular version of your particular compiler may, or
may not, generate code that you think makes sense if you do the above. But that’s the point: since
the compiler is not required to generate sensible code, you don’t know what the compiler will do.
So please do not email us saying your particular compiler generates good code; we don’t care. It’s
still illegal. See the C++ standard for more, for example, C++ 2014 section 8.3.2 [dcl.ref] p5.
By way of example and not by way of limitation, some compilers do optimize nullptr tests since
they “know” all references refer to real objects — that references are never (legally) a
dereferenced nullptr. That can cause a compiler to optimize away the following test:
1. // ...the above code...
2. T* p2 = &r;
3. if (p2 == nullptr) {
4. // ...
5. }
As stated above, this is just an example of the sort of thing your compiler might do based on the
language rule that says a reference must refer to a valid object. Do not limit your thinking to the
above example; the message of this FAQ is that the compiler is not required to do something
sensible if you violate the rules. So don’t violate the rules.
Patient: “Doctor, doctor, my eye hurts when I poke it with a spoon.”
Doctor: “Don’t poke it, then.”
So if your ultimate goal is to enable a glop of code to uniquely identify/look-up a specific object of
some class Fred, you need to pass a Fred handle into that glop of code. The handle might be a
string that can be used as a key in some well-known lookup table (e.g., a key in
a std::map<std::string,Fred> or a std::map<std::string,Fred*>), or it might be an
integer that would be an index into some well-known array (e.g., Fred* array = new
Fred[maxNumFreds]), or it might be a simple Fred*, or it might be something else.
Novices often think in terms of pointers, but in reality there are downside risks to using raw
pointers. E.g., what if the Fred object needs to move? How do we know when it’s safe
to delete the Fred objects? What if the Fred object needs to (temporarily) get serialized on disk?
etc., etc. Most of the time we add more layers of indirection to manage situations like these. For
example, the handles might be Fred**, where the pointed-to Fred* pointers are guaranteed to
never move but when the Fred objects need to move, you just update the pointed-
to Fred* pointers. Or you make the handle an integer then have the Fred objects (or pointers to
the Fred objects) looked up in a table/array/whatever. Or whatever.
The point is that we use the word Handle when we don’t yet know the details of what we’re going
to do.
Another time we use the word Handle is when we want to be vague about what we’ve already done
(sometimes the term magic cookie is used for this as well, as in, “The software passes around
a magic cookie that is used to uniquely identify and locate the appropriate Fred object”). The
reason we (sometimes) want to be vague about what we’ve already done is to minimize the ripple
effect if/when the specific details/representation of the handle change. E.g., if/when someone
changes the handle from a string that is used in a lookup table to an integer that is looked up in an
array, we don’t want to go and update a zillion lines of code.
To further ease maintenance if/when the details/representation of a handle changes (or to generally
make the code easier to read/write), we often encapsulate the handle in a class. This class
often overloads operators operator-> and operator* (since the handle acts like a pointer, it
might as well look like a pointer).
If you want to change the object passed, call by reference or use a pointer; e.g., void
f(X&); or void f(X*);.
If you don’t want to change the object passed and it is big, call by const reference; e.g., void
f(const X&);.
Otherwise, call by value; e.g. void f(X);.
What does “big” mean? Anything larger than a couple of words.
Why would you want to change an argument? Well, often we have to, but often we have an
alternative: produce a new value. Consider:
1. void incr1(int& x); // increment
2. int incr2(int x); // increment
3.
4. int v = 2;
5. incr1(v); // v becomes 3
6. v = incr2(v); // v becomes 4
For a reader, incr2() is likely easier to understand. That is, incr1() is more likely to lead to
mistakes and errors. So, we should prefer the style that returns a new value over the one that
modifies a value as long as the creation and copy of a new value isn’t expensive.
What if you do want to change the argument, should you use a pointer or use a reference? If
passing “not an object” (e.g., a null pointer) is acceptable, using a pointer makes sense. One style is
to use a pointer when you want to modify an object because in some contexts that makes it easier to
spot that a modification is possible.
Note also that a call of a member function is essentially a call-by-reference on the object, so we
often use member functions when we want to modify the value/state of an object.
Memory Management
Save to:
InstapaperPocketReadability
Contents of this section:
What are the two steps that happen when I say delete
p?
delete p is a two-step process: it calls the destructor, then releases the memory. The code
generated for delete p is functionally similar to this (assuming p is of type Fred*):
1. // Original code: delete p;
2. if (p) { // or "if (p != nullptr)"
3. p->~Fred();
4. operator delete(p);
5. }
The statement p->~Fred() calls the destructor for the Fred object pointed to by p.
The statement operator delete(p) calls the memory deallocation primitive, void operator
delete(void* p). This primitive is similar in spirit to free(void* p). (Note, however, that
these two are not interchangeable; e.g., there is no guarantee that the two memory deallocation
primitives even use the same heap!)
Why doesn’t delete null out its operand?
First, you should normally be using smart pointers, so you won’t care – you won’t be
writing delete anyway.
For those rare cases where you really are doing manual memory management and so do care,
consider:
1. delete p;
2. // ...
3. delete p;
If the ... part doesn’t touch p then the second delete p; is a serious error that a C++
implementation cannot effectively protect itself against (without unusual precautions). Since
deleting a null pointer is harmless by definition, a simple solution would be for delete p; to do
a p=nullptr; after it has done whatever else is required. However, C++ doesn’t guarantee that.
One reason is that the operand of delete need not be an lvalue. Consider:
1. delete p+1;
2. delete f(x);
Here, the implementation of delete does not have a pointer to which it can null out. These
examples may be rare, but they do imply that it is not possible to guarantee that “any pointer to a
deleted object is null.” A simpler way of bypassing that “rule” is to have two pointers to an object:
1. T* p = new T;
2. T* q = p;
3. delete p;
4. delete q; // ouch!
C++ explicitly allows an implementation of delete to null out an lvalue operand, but that idea
doesn’t seem to have become popular with implementers.
If you consider zeroing out pointers important, consider using a destroy function:
1. template<class T> inline void destroy(T*& p) { delete p; p = 0; }
Consider this yet-another reason to minimize explicit use of new and delete by relying on
standard library smart pointers, containers, handles, etc.
Note that passing the pointer as a reference (to allow the pointer to be nulled out) has the added
benefit of preventing destroy() from being called for an rvalue:
1. int* f();
2. int* p;
3. // ...
4. destroy(f()); // error: trying to pass an rvalue by non-const reference
5. destroy(p+1); // error: trying to pass an rvalue by non-const reference
What is a class?
What is an object?
When is an interface “good”?
What is encapsulation?
How does C++ help with the tradeoff of safety vs. usability?
How can I prevent other programmers from violating encapsulation by seeing
the private parts of my class?
Can a method directly access the non-public members of another instance of its class?
Is Encapsulation a Security device?
What’s the difference between the keywords struct and class?
How do I define an in-class constant?
Why do I have to put the data in my class declarations?
How are C++ objects laid out in memory?
Why is the size of an empty class not zero?
What is a class?
The fundamental building block of OO software.
A class defines a data type, much like a struct would be in C. In a computer science sense, a
type consists of both a set of states and a set of operations which transition between those states.
Thus int is a type because it has both a set of states and it has operations like i + j or i++, etc. In
exactly the same way, a class provides a set of (usually public) operations, and a set of (usually
non-public) data bits representing the abstract values that instances of the type can have.
You can imagine that int is a class that has member functions called operator++, etc.
(int isn’t really a class, but the basic analogy is this: a class is a type, much like int is a type.)
Note: a C programmer can think of a class as a C struct whose members default to private.
But if that’s all you think of a class, then you probably need to experience a personal paradigm
shift.
What is an object?
A region of storage with associated semantics.
After the declaration int i; we say that “i is an object of type int.” In OO/C++, “object” usually
means “an instance of a class.” Thus a class defines the behavior of possibly many objects
(instances).
When is an interface “good”?
When it provides a simplified view of a chunk of software, and it is expressed in the vocabulary of a
user (where a “chunk” is normally a class or a tight group of classes, and a “user” is another
developer rather than the ultimate customer).
The “simplified view” means unnecessary details are intentionally hidden. This reduces the
user’s defect-rate.
The “vocabulary of users” means users don’t need to learn a new set of words and concepts.
This reduces the user’s learning curve.
What is encapsulation?
Preventing unauthorized access to some piece of information or functionality.
The key money-saving insight is to separate the volatile part of some chunk of software from the
stable part. Encapsulation puts a firewall around the chunk, which prevents other chunks from
accessing the volatile parts; other chunks can only access the stable parts. This prevents the other
chunks from breaking if (when!) the volatile parts are changed. In context of OO software, a
“chunk” is normally a class or a tight group of classes.
The “volatile parts” are the implementation details. If the chunk is a single class, the volatile part is
normally encapsulated using the private and/or protected keywords. If the chunk is a tight
group of classes, encapsulation can be used to deny access to entire classes in that
group. Inheritance can also be used as a form of encapsulation.
The “stable parts” are the interfaces. A good interface provides a simplified view in the vocabulary
of a user, and is designed from the outside-in (here a “user” means another developer, not the end-
user who buys the completed application). If the chunk is a single class, the interface is simply the
class’s public member functions and friend functions. If the chunk is a tight group of classes,
the interface can include several of the classes in the chunk.
Designing a clean interface and separating that interface from its
implementation merely allows users to use the interface. But encapsulating (putting “in a capsule”)
the implementation forces users to use the interface.
How does C++ help with the tradeoff of safety vs.
usability?
In C, encapsulation was accomplished by making things static in a compilation unit or module.
This prevented another module from accessing the static stuff. (By the way, static data at file-
scope is now deprecated in C++: don’t do that.)
Unfortunately this approach doesn’t support multiple instances of the data, since there is no direct
support for making multiple instances of a module’s static data. If multiple instances were
needed in C, programmers typically used a struct. But unfortunately C structs don’t
support encapsulation. This exacerbates the tradeoff between safety (information hiding) and
usability (multiple instances).
In C++, you can have both multiple instances and encapsulation via a class. The public part of a
class contains the class’s interface, which normally consists of the class’s public member
functions and its friend functions. The private and/or protected parts of a class contain the
class’s implementation, which is typically where the data lives.
The end result is like an “encapsulated struct.” This reduces the tradeoff between safety
(information hiding) and usability (multiple instances).
How can I prevent other programmers from violating
encapsulation by seeing the private parts of my class?
Not worth the effort — encapsulation is for code, not people.
It doesn’t violate encapsulation for a programmer to see the private and/or protected parts of
your class, so long as they don’t write code that somehow depends on what they saw. In other
words, encapsulation doesn’t prevent people from knowing about the inside of a class; it prevents
the code they write from becoming dependent on the insides of the class. Your company doesn’t
have to pay a “maintenance cost” to maintain the gray matter between your ears; but it does have to
pay a maintenance cost to maintain the code that comes out of your finger tips. What you know as a
person doesn’t increase maintenance cost, provided the code you write depends on the interface
rather than the implementation.
Besides, this is rarely if ever a problem. I don’t know any programmers who have intentionally tried
to access the private parts of a class. “My recommendation in such cases would be to change the
programmer, not the code” [James Kanze; used with permission].
Can a method directly access the non-public members of
another instance of its class?
Yes.
The name this is not special. Access is granted or denied based on the class of the
reference/pointer/object, not based on the name of the reference/pointer/object. (See below for the
fine print.)
The fact that C++ allows a class’ methods and friends to access the non-public parts of all its
objects, not just the this object, seems at first to weaken encapsulation. However the opposite is
true: this rule preserves encapsulation. Here’s why.
Without this rule, most non-public members would need a public get method, because many
classes have at least one method or friend that takes an explicit argument (i.e., an argument not
called this) of its own class.
Huh? (you ask). Let’s kill the mumbo jumbo and work out an example:
Consider assignment operator Foo::operator=(const Foo& x). This assignment operator will
probably change the data members in the left-hand argument, *this, based on the data members in
the right-hand argument, x. Without the C++ rule being discussed here, the only way for that
assignment operator to access the non-public members of x would be for class Foo to provide
a public get method for every non-public datum. That would suck bigtime. (NB: “suck bigtime”
is a precise, sophisticated, technical term; and I am writing this on April 1.)
The assignment operator isn’t the only one that would weaken encapsulation were it not for this
rule. Here is a partial(!) list of others:
Copy constructor.
Comparison operators: ==, !=, <=, <, >=, >.
Binary arithmetic operators: x+y, x-y, x*y, x/y, x%y.
Binary bitwise operators: x^y, x&y, x|y.
Static methods that accepts an instance of the class as a parameter.
Static methods that creates/manipulates an instance of the class.
etc.
Conclusion: encapsulation would be shredded without this beneficial rule: most non-
public members of most classes would end up having a public get method.
The Fine Print: There is another rule that is related to the above: methods and friends of a derived
class can access the protected base class members of any of its own objects (any objects of its
class or any derived class of its class), but not others. Since that is hopelessly opaque, here’s an
example: suppose classes D1 and D2 inherit directly from class B, and base
class B has protected member x. The compiler will let D1’s members and friends directly access
the x member of any object it knows to be at least a D1, such as via a D1* pointer, a D1& reference,
a D1 object, etc. However the compiler will give a compile-time error if a D1 member or friend tries
to directly access the x member of anything it does not know is at least a D1, such as via
a B* pointer, a B& reference, a B object, a D2* pointer, a D2& reference, a D2 object, etc. By way of
(imperfect!!) analogy, you are allowed to pick your own pockets, but you are not allowed to pick
your father’s pockets nor your brother’s pockets.
Is Encapsulation a Security device?
No.
Encapsulation != security.
Encapsulation prevents mistakes, not espionage.
Constructors
Save to:
InstapaperPocketReadability
Contents of this section:
Destructors
Save to:
InstapaperPocketReadability
Contents of this section:
Assignment Operators
Save to:
InstapaperPocketReadability
Contents of this section:
Operator Overloading
Save to:
InstapaperPocketReadability
Contents of this section:
Friends
Save to:
InstapaperPocketReadability
Contents of this section:
What is a friend?
Do friends violate encapsulation?
What are some advantages/disadvantages of using friend functions?
What does it mean that “friendship isn’t inherited, transitive, or reciprocal”?
Should my class declare a member function or a friend function?
What is a friend?
Something to allow your class to grant access to another class or function.
Friends can be either functions or other classes. A class grants access privileges to its friends.
Normally a developer has political and technical control over both the friend and member
functions of a class (else you may need to get permission from the owner of the other pieces when
you want to update your own class).
Do friends violate encapsulation?
No! If they’re used properly, they enhance encapsulation.
“Friend” is an explicit mechanism for granting access, just like membership. You cannot (in a
standard conforming program) grant yourself access to a class without modifying its source. For
example:
1. class X {
2. int i;
3. public:
4. void m(); // grant X::m() access
5. friend void f(X&); // grant f(X&) access
6. // ...
7. };
8.
9. void X::m() { i++; /* X::m() can access X::i */ }
10.
11. void f(X& x) { x.i++; /* f(X&) can access X::i */ }
For a description on the C++ protection model, see D&E sec 2.10 and TC++PL sec 11.5, 15.3, and
C.11.
You often need to split a class in half when the two halves will have different numbers of instances
or different lifetimes. In these cases, the two halves usually need direct access to each other (the two
halves used to be in the same class, so you haven’t increased the amount of code that needs direct
access to a data structure; you’ve simply reshuffled the code into two classes instead of one). The
safest way to implement this is to make the two halves friends of each other.
If you use friends like just described, you’ll keep private things private. People who don’t
understand this often make naive efforts to avoid using friendship in situations like the above, and
often they actually destroy encapsulation. They either use public data (grotesque!), or they make
the data accessible between the halves via public get() and set() member functions. Having
a public get() and set() member function for a private datum is okay only when
the private datum “makes sense” from outside the class (from a user’s perspective). In many
cases, these get()/set() member functions are almost as bad as public data: they hide (only)
the name of the private datum, but they don’t hide the existence of the private datum.
Similarly, if you use friend functions as a syntactic variant of a class’s public access functions,
they don’t violate encapsulation any more than a member function violates encapsulation. In other
words, a class’s friends don’t violate the encapsulation barrier: along with the class’s member
functions, they are the encapsulation barrier.
(Many people think of a friend function as something outside the class. Instead, try thinking of a
friend function as part of the class’s public interface. A friend function in the class declaration
doesn’t violate encapsulation any more than a public member function violates encapsulation: both
have exactly the same authority with respect to accessing the class’s non-public parts.)
Inheritance — Basics
Save to:
InstapaperPocketReadability
Contents of this section:
Inheritance
— private and protected inheritance
Save to:
InstapaperPocketReadability
Contents of this section:
Templates
Save to:
InstapaperPocketReadability
Contents of this section:
Container Classes
Save to:
InstapaperPocketReadability
Contents of this section:
Class Libraries
Save to:
InstapaperPocketReadability
Contents of this section:
Inline Functions
Save to:
InstapaperPocketReadability
Contents of this section:
C++11 Overview
Save to:
InstapaperPocketReadability
Contents of this section:
C++11: Purpose of this FAQ section
What is C++11?
What is C++0x?
When will compilers implement C++11?
How did the committee approach picking new language and library features for C++11?
What were the general design goals of the C++11 effort?
What specific design goals guided the committee?
Where can I find the committee papers for C++11 features?
Where can I find academic and technical papers about C++11?
Where else can I read about C++11?
Are there any videos about C++11?
Is C++11 hard to learn?
Is C++11 the final C++ standard?
C++11: Purpose of this FAQ section
The purpose of this FAQ’s C++11 sections (including this section) is:
To give an overview of the new facilities (language features and standard libraries) offered
by C++11 in addition to what is provided by the previous version of the ISO C++ standard.
To give an idea of the aims of the ISO C++ standards effort.
To present a user’s view of the new facilities
To provide references to allow for a more in depth study of features.
To name many of the individuals who contributed (mostly as authors of the reports they
wrote for the committee). The standard is not written by a faceless organization.
We often borrow examples from the proposals. In those cases: Thanks to the proposal authors.
Many other examples are borrowed from Stroustrup’s talks and papers.
Please note that the purpose of this FAQ is not to provide comprehensive discussion of individual
features or a detailed explanation of how to use them. The aim is to give simple examples to
demonstrate what C++11 has to offer (plus references). Our ideal is “max one page per feature”
independently of how complex a feature is. Details can often be found in the references.
See the FAQ Home page for a list of all C++11 sections.
What is C++11?
C++11 is the ISO C++ standard formally ratified by a 21-0 national vote in August 2011.
This public working paper is the January 2012 working draft, and contains the C++11 standard plus
minor editorial changes.
C++11 is a major upgrade over C++98/03, with performance and convenience features that make it
feel like a new language.
The previous (and first) standard is often referred to as C++98 or C++03; the differences between
C++98 and C++03 are so few and so technical that they ought not concern users. This FAQ
discusses changes between C++98/C++03 to C++11.
What is C++0x?
The “under-development” name for C++11. Before its official ratification in 2011, the then-under-
development standard was unofficially called C++0x, as it was hoped to be completed in C++08 or
C++09. Think of ‘x’ as hexadecimal (i.e., C++0B == C++11).
When will compilers implement C++11?
Currently shipping compilers (e.g. GCC C++, Clang C++, IBM C++, and Microsoft C++) already
implement most or all C++11 features, and are working on C++14 features.
Modulo bugs, the first fully conforming C++11 language implementation was GCC 4.8.1 (May 31,
2013) but it still did not have a conforming standard library. The first complete C++11
implementation, including both the language and the standard library, was Clang 3.3 (June 5, 2013).
Here are links to C++11 information from purveyors:
comparison
GCC
IBM
Microsoft
EDG
Clang
How did the committee approach picking new language
and library features for C++11?
You don’t improve a language by simply adding every feature that someone considers a good idea.
In fact, essentially every feature of most modern languages has been suggested for C++ by
someone: Try to imagine what the union of C99, C#, Java, Haskell, Lisp, Python, and Ada would
look like. To make the problem more difficult, remember that it is not feasible to eliminate older
features, even in the reasonably rare cases when the committee agrees that they are bad: Experience
shows that users force every implementer to keep providing deprecated and banned features under
compatibility switches (or by default) for decades.
In addition to the general design goals, to try to select rationally from the flood of suggestions the
committee devised a set of specific design goals. The result has been a language with greatly
improved abstraction mechanisms. The range of abstractions that C++ can express elegantly,
flexibly, and at zero cost compared to hand-crafted specialized code has greatly increased. When we
say “abstraction” people often just think “classes” or “objects.” C++11 goes far beyond that: The
range of user-defined types that can be cleanly and safely expressed has grown with the addition of
features such as initializer-lists, uniform initialization, template aliases, rvalue references, defaulted
and deleted functions, and variadic templates. Their implementation eased with features, such
as auto, inherited constructors, and decltype. These enhancements are sufficient to make C++11 feel
like a new language.
For information about accepted language features, see the C++11 language extensions sections of
this FAQ, listed on the FAQ Home page.
The standard library definition is already about 70% of the normative text of the standard (and that
doesn’t count the C standard library, which is included by reference). Even though some members
would have liked to see many more standard libraries, nobody could claim that the Library Working
Group has been lazy. It is also worth noting that the C++98 libraries have been significantly
improved through the use of new language features, such as initializer-lists, rvalue
references, variadic templates, noexcept, and constexpr. The C++11 standard library is easier to
use and provides better performance than the C++98 one.
For information about accepted library features, see the C++11 library extensions sections of this
FAQ, listed on the FAQ Home page.
auto
decltype
Range-for statement
Initializer lists
Uniform initialization syntax and semantics
Rvalue references and move semantics
Lambdas
noexcept to prevent exception propagation
constexpr
nullptr – a null pointer literal
Copying and rethrowing exceptions
Inline namespaces
User-defined literals
auto
Consider
1. auto x = 7;
Here x will have the type int because that’s the type of its initializer. In general, we can write
1. auto x = expression;
and the type of x will be the type of the value computed from “expression”.
The use of auto to deduce the type of a variable from its initializer is obviously most useful when
that type is either hard to know exactly or hard to write. Consider:
1. template<class T> void printall(const vector<T>& v)
2. {
3. for (auto p = v.begin(); p!=v.end(); ++p)
4. cout << *p << "\n";
5. }
In C++98, we’d have to write
1. template<class T> void printall(const vector<T>& v)
2. {
3. for (typename vector<T>::const_iterator p = v.begin(); p!=v.end(); ++p)
4. cout << *p << "\n";
5. }
When the type of a variable depends critically on template argument it can be really hard to write
code without auto. For example:
1. template<class T, class U> void multiply(const vector<T>& vt, const vector<U>& vu)
2. {
3. // ...
4. auto tmp = vt[i]*vu[i];
5. // ...
6. }
The type of tmp should be what you get from multiplying a T by a U, but exactly what that is can be
hard for the human reader to figure out, though of course the compiler knows once it has figured out
what particular T and U it is dealing with.
The auto feature has the distinction to be the earliest to be suggested and implemented: Stroustrup
had it working in his Cfront implementation in early 1984, but was forced to take it out because of
C compatibility problems. Those compatibility problems disappeared when C++98 and C99
accepted the removal of “implicit int”; that is, both languages now require every variable and
function to be defined with an explicit type. The old meaning of auto (namely “this is a local
variable”) is now illegal. Several committee members trawled through millions of lines of code
finding only a handful of uses – and most of those were in test suites or appeared to be bugs.
Being primarily a facility to simplify notation in code, auto does not affect the standard library
specification.
See also:
the C++ draft section 7.1.6.2, 7.1.6.4, 8.3.5 (for return types)
[N1984=06-0054] Jaakko Jarvi, Bjarne Stroustrup, and Gabriel Dos Reis: Deducing the type
of variable from its initializer expression (revision 4).
Herb Sutter: GotW #92: Auto Variables, Part 1
Herb Sutter: GotW #93: Auto Variables, Part 2
Herb Sutter: GotW #94: AAA Style (Almost Always Auto)
decltype
decltype(E) is the type (“declared type”) of the name or expression E and can be used in
declarations. For example:
1. void f(const vector<int>& a, vector<float>& b)
2. {
3. typedef decltype(a[0]*b[0]) Tmp;
4. for (int i=0; i<b.size(); ++i) {
5. Tmp* p = new Tmp(a[i]*b[i]);
6. // ...
7. }
8. // ...
9. }
This notion has been popular in generic programming under the label “typeof” for a long time, but
the “typeof” implementations in actual use were incomplete and incompatible, so the standard
version is named decltype.
Note: Prefer just using auto when you just need the type for a variable that you are about to
initialize. You really need decltype if you need a type for something that is not a variable, such as
a return type.
See also:
the C++ draft 7.1.6.2 Simple type specifiers
[Str02] Bjarne Stroustrup. Draft proposal for “typeof”. C++ reflector message c++std-ext-
5364, October 2002. (original suggestion).
[N1478=03-0061] Jaakko Jarvi, Bjarne Stroustrup, Douglas Gregor, and Jeremy
Siek: Decltype and auto (original proposal).
[N2343=07-0203] Jaakko Jarvi, Bjarne Stroustrup, and Gabriel Dos Reis: Decltype (revision
7): proposed wording.
Range-for statement
A range for statement allows you to iterate through a “range”, which is anything you can iterate
through like an STL-sequence defined by a begin() and end(). All standard containers can be
used as a range, as can a std::string, an initializer list, an array, and anything for which you
define begin() and end(), e.g. an istream. For example:
1. void f(vector<double>& v)
2. {
3. for (auto x : v) cout << x << '\n';
4. for (auto& x : v) ++x; // using a reference to allow us to change the value
5. }
You can read that as “for all x in v” going through starting with v.begin() and iterating
to v.end(). Another example:
1. for (const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << '\n';
The begin() (and end()) can be a member to be called as x.begin() or a free-standing function
to be called as begin(x). The member version takes precedence.
See also:
the C++ draft section 6.5.4 (note: changed not to use concepts)
[N2243==07-0103] Thorsten Ottosen: Wording for range-based for-loop (revision 2).
[N3257=11-0027 ] Jonathan Wakely and Bjarne Stroustrup: Range-based for statements and
ADL (Option 5 was chosen).
Initializer lists
Consider
1. vector<double> v = { 1, 2, 3.456, 99.99 };
2. list<pair<string,string>> languages = {
3. {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
4. };
5. map<vector<string>,vector<int>> years = {
6. { {"Maurice","Vincent", "Wilkes"},{1913, 1945, 1951, 1967, 2000} },
7. { {"Martin", "Ritchards"}, {1982, 2003, 2007} },
8. { {"David", "John", "Wheeler"}, {1927, 1947, 1951, 2004} }
9. };
Initializer lists are not just for arrays any more. The mechanism for accepting a {}-list is a function
(often a constructor) accepting an argument of type std::initializer_list<T>. For example:
1. void f(initializer_list<int>);
2. f({1,2});
3. f({23,345,4567,56789});
4. f({}); // the empty list
5. f{1,2}; // error: function call ( ) missing
6.
7. years.insert({{"Bjarne","Stroustrup"},{1950, 1975, 1985}});
The initializer list can be of arbitrary length, but must be homogeneous (all elements must be of the
template argument type, T, or convertible to T).
A container might implement an initializer-list constructor like this:
1. template<class E> class vector {
2. public:
3. vector (std::initializer_list<E> s) // initializer-list constructor
4. {
5. reserve(s.size()); // get the right amount of space
6. uninitialized_copy(s.begin(), s.end(), elem); // initialize elements (in elem[0:s.size()))
7. sz = s.size(); // set vector size
8. }
9.
10. // ... as before ...
11. };
The distinction between direct initialization and copy initialization is maintained for {}-
initialization, but becomes relevant less frequently because of {}-initialization. For
example, std::vector has an explicit constructor from int and
an initializer_list constructor:
1. vector<double> v1(7); // ok: v1 has 7 elements
2. v1 = 9; // error: no conversion from int to vector
3. vector<double> v2 = 9; // error: no conversion from int to vector
4.
5. void f(const vector<double>&);
6. f(9); // error: no conversion from int to vector
7.
8. vector<double> v1{7}; // ok: v1 has 1 element (with its value 7.0)
9. v1 = {9}; // ok v1 now has 1 element (with its value 9.0)
10. vector<double> v2 = {9}; // ok: v2 has 1 element (with its value 9.0)
11. f({9}); // ok: f is called with the list { 9 }
12.
13. vector<vector<double>> vs = {
14. vector<double>(10), // ok: explicit construction (10 elements)
15. vector<double>{10}, // ok explicit construction (1 element with the value 10.0)
16. 10 // error: vector's constructor is explicit
17. };
The function can access the initializer_list as an immutable sequence. For example:
1. void f(initializer_list<int> args)
2. {
3. for (auto p=args.begin(); p!=args.end(); ++p) cout << *p << "\n";
4. }
A constructor that takes a single argument of type std::initializer_list is called an
initializer-list constructor.
The standard library containers, string, and regex have initializer-list constructors, assignment,
etc. An initializer-list can be used as a range, e.g. in a range for statement.
The initializer lists are part of the scheme for uniform and general initialization. They also prevent
narrowing. In general, you should usually prefer initializing using {} instead of () unless you want
to share code with a C++98 compiler or (rarely) need to use () to call a non-
initializer_list overloaded constructor.
See also:
the C++ draft 8.5.4 List-initialization [dcl.init.list]
[N1890=05-0150 ] Bjarne Stroustrup and Gabriel Dos Reis: Initialization and initializers (an
overview of initialization-related problems with suggested solutions).
[N1919=05-0179] Bjarne Stroustrup and Gabriel Dos Reis: Initializer lists.
[N2215=07-0075] Bjarne Stroustrup and Gabriel Dos Reis: Initializer lists (Rev. 3).
[N2640=08-0150] Jason Merrill and Daveed Vandevoorde: Initializer Lists – Alternative
Mechanism and Rationale (v. 2) (final proposal).
Uniform initialization syntax and semantics
C++98 offers several ways of initializing an object depending on its type and the initialization
context. When misused, the error can be surprising and the error messages obscure. Consider:
1. string a[] = { "foo", " bar" }; // ok: initialize array variable
2. vector<string> v = { "foo", " bar" }; // error: initializer list for non-aggregate vector
3. void f(string a[]);
4. f( { "foo", " bar" } ); // syntax error: block as argument
and
1. int a = 2; // "assignment style"
2. int aa[] = { 2, 3 }; // assignment style with list
3. complex z(1,2); // "functional style" initialization
4. x = Ptr(y); // "functional style" for conversion/cast/construction
and
1. int a(1); // variable definition
2. int b(); // function declaration
3. int b(foo); // variable definition or function declaration
It can be hard to remember the rules for initialization and to choose the best way.
The C++11 solution is to allow {}-initializer lists for all initialization:
1. X x1 = X{1,2};
2. X x2 = {1,2}; // the = is optional
3. X x3{1,2};
4. X* p = new X{1,2};
5.
6. struct D : X {
7. D(int x, int y) :X{x,y} { /* ... */ };
8. };
9.
10. struct S {
11. int a[3];
12. S(int x, int y, int z) :a{x,y,z} { /* ... */ }; // solution to old problem
13. };
Importantly, X{a} constructs the same value in every context, so that {}-initialization gives the
same result in all places where it is legal. For example:
1. X x{a};
2. X* p = new X{a};
3. z = X{a}; // use as cast
4. f({a}); // function argument (of type X)
5. return {a}; // function return value (function returning X)
C++11 uniform initialization is not perfectly uniform, but it’s very nearly so. C+
+11’s {} initialization syntax and semantics provide a much simpler and consistent way to perform
initialization, that is also more powerful (e.g., vector<int> v = { 1, 2, 3, 4 }) and safer
(e.g., {} does not allow narrowing conversions). Prefer initializing using {}.
See also:
[N2215==07-0075 ] Bjarne Stroustrup and Gabriel Dos Reis: Initializer lists (Rev. 3).
[N2640==08-0150] Jason Merrill and Daveed Vandevoorde: Initializer Lists – Alternative
Mechanism and Rationale (v. 2) (final proposal).
Rvalue references and move semantics
The distinction between lvalues (what can be used on the left-hand side of an assignment) and
rvalues (what can be used on the right-hand side of an assignment) goes back to Christopher
Strachey (the father of C++’s distant ancestor CPL and of denotational semantics). In C++98,
references to non-const can bind to lvalues and references to const can bind to lvalues or rvalues,
but there is nothing that can bind to a non-const rvalue. That’s to protect people from changing the
values of temporaries that are destroyed before their new value can be used. For example:
1. void incr(int& a) { ++a; }
2. int i = 0;
3. incr(i); // i becomes 1
4. incr(0); // error: 0 in not an lvalue
If that incr(0) were allowed either some temporary that nobody ever saw would be incremented
or – far worse – the value of 0 would become 1. The latter sounds silly, but there was actually a bug
like that in early Fortran compilers that set aside a memory location to hold the value 0.
So far, so good, but consider
1. template<class T> swap(T& a, T& b) // "old style swap"
2. {
3. T tmp(a); // now we have two copies of a
4. a = b; // now we have two copies of b
5. b = tmp; // now we have two copies of tmp (aka a)
6. }
If T is a type for which it can be expensive to copy elements, such
as string and vector, swap becomes an expensive operation (for the standard library, we have
specializations of string and vector swap() to deal with that). Note something curious: We
didn’t want any copies at all. We just wanted to move the values of a, b, and tmp around a bit.
In C++11, we can define “move constructors” and “move assignments” to move rather than copy
their argument:
1. template<class T> class vector {
2. // ...
3. vector(const vector&); // copy constructor
4. vector(vector&&); // move constructor
5. vector& operator=(const vector&); // copy assignment
6. vector& operator=(vector&&); // move assignment
7. }; // note: move constructor and move assignment takes non-const &&
8. // they can, and usually do, write to their argument
The && indicates an “rvalue reference”. An rvalue reference can bind to an rvalue (but not to an
lvalue):
1. X a;
2. X f();
3. X& r1 = a; // bind r1 to a (an lvalue)
4. X& r2 = f(); // error: f() is an rvalue; can't bind
5.
6. X&& rr1 = f(); // fine: bind rr1 to temporary
7. X&& rr2 = a; // error: bind a is an lvalue
The idea behind a move assignment is that instead of making a copy, it simply takes the
representation from its source and replaces it with a cheap default. For example,
for strings s1=s2 using the move assignment would not make a copy of s2’s characters; instead,
it would just let s1 treat those characters as its own and somehow delete s1’s old characters (maybe
by leaving them in s2, which presumably is just about to be destroyed).
How do we know whether it’s ok to simply move from a source? We tell the compiler:
1. template<class T>
2. void swap(T& a, T& b) // "perfect swap" (almost)
3. {
4. T tmp = move(a); // could invalidate a
5. a = move(b); // could invalidate b
6. b = move(tmp); // could invalidate tmp
7. }
move(x) is just a cast that means “you can treat x as an rvalue”. Maybe it would have been better
if move() had been called rval(), but by now move() has been used for years.
The move() template function can be written in C++11 (see the “brief introduction”) and and uses
rvalue references.
Rvalue references can also be used to provide perfect forwarding.
In the C++11 standard library, all containers are provided with move constructors and move
assignments, and operations that insert new elements, such as insert() and push_back(), have
versions that take rvalue references. The net result is that the standard containers and algorithms
quietly – without user intervention – improve in performance because they copy less.
See also:
N1385 N1690 N1770 N1855 N1952
[N2027==06-0097] Howard Hinnant, Bjarne Stroustrup, and Bronek Kozicki: A brief
introduction to rvalue references
[N1377=02-0035] Howard E. Hinnant, Peter Dimov, and Dave Abrahams: A Proposal to
Add Move Semantics Support to the C++ Language (original proposal).
[N2118=06-0188] Howard Hinnant: A Proposal to Add an Rvalue Reference to the C++
Language Proposed Wording (Revision 3) (final proposal).
Lambdas
A lambda expression is a mechanism for specifying a function object. The primary use for a lambda
is to specify a simple action to be performed by some function. For example:
1. vector<int> v = {50, -10, 20, -30};
2.
3. std::sort(v.begin(), v.end()); // the default sort
4. // now v should be { -30, -10, 20, 50 }
5.
6. // sort by absolute value:
7. std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a)<abs(b); });
8. // now v should be { -10, 20, -30, 50 }
The argument [](int a, int b) { return abs(a)<abs(b); } is a “lambda” (or “lambda
function” or “lambda expression”), which specifies an operation that given two integer
arguments a and b returns the result of comparing their absolute values.
A lambda expression can access local variables in the scope in which it is used. For example:
1. void f(vector<Record>& v)
2. {
3. vector<int> indices(v.size());
4. int count = 0;
5. generate(indices.begin(),indices.end(),[&count](){ return count++; });
6.
7. // sort indices in the order determined by the name field of the records:
8. std::sort(indices.begin(), indices.end(), [&](int a, int b) { return v[a].name<v[b].name; });
9. // ...
10. }
Some consider this “really neat!”; others see it as a way to write dangerously obscure code. Both are
right.
The [&] is a “capture list” specifying that local names used will be passed by reference. Had we
wanted to “capture” only v, we could have said so: [&v]. Had we wanted to pass v by value, we
could have said so: [=v] or [v]. Capture nothing is [], capture all by reference is [&], and capture
all by value is [=].
If an action is neither common nor simple, consider using a named function object or function. For
example, the example above could have been written:
1. void f(vector<Record>& v)
2. {
3. vector<int> indices(v.size());
4. int count = 0;
5. generate(indices.begin(),indices.end(),[&](){ return ++count; });
6.
7. struct Cmp_names {
8. const vector<Record>& vr;
9. Cmp_names(const vector<Record>& r) :vr(r) { }
10. bool operator()(int a, int b) const { return vr[a].name<vr[b].name; }
11. };
12.
13. // sort indices in the order determined by the name field of the records:
14. std::sort(indices.begin(), indices.end(), Cmp_names(v));
15. // ...
16. }
For a tiny function, such as this Record name field comparison, the function object notation is
verbose, though the generated code is likely to be identical. In C++98, such function objects had to
be non-local to be used as template argument; in C++ this is no longer necessary.
To specify a lambda you must provide
Its capture list: the list of variables it can use (in addition to its arguments), if any
([&] meaning “all local variables passed by reference” in the Record comparison example). If no
names need to be captured, a lambda starts with plain [].
(optionally) Its arguments and their types (e.g, (int a, int b))
The action to be performed as a block (e.g., { return v[a].name<v[b].name; }).
(optionally) The return type using the new suffix return type syntax; but typically we just
deduce the return type from the return statement. If no value is returned then void is deduced.
See also:
Standard 5.1.2 Lambda expressions
[N1968=06-0038] Jeremiah Willcock, Jaakko Jarvi, Doug Gregor, Bjarne Stroustrup, and
Andrew Lumsdaine: Lambda expressions and closures for C++ (original proposal with a different
syntax)
[N2550=08-0060] Jaakko Jarvi, John Freeman, and Lawrence Crowl: Lambda Expressions
and Closures: Wording for Monomorphic Lambdas (Revision 4) (final proposal).
[N2859=09-0049] Daveed Vandevoorde: New wording for C++0x Lambdas.
noexcept to prevent exception propagation
If a function cannot throw an exception or if the program isn’t written to handle exceptions thrown
by a function, that function can be declared noexcept. For example:
1. extern "C" double sqrt(double) noexcept; // will never throw
2.
3. vector<double> my_computation(const vector<double>& v) noexcept // I'm not prepared to handle
memory exhaustion
4. {
5. vector<double> res(v.size()); // might throw
6. for(int i; i<v.size(); ++i) res[i] = sqrt(v[i]);
7. return res;
8. }
If a function declared noexcept throws (so that the exception tries to escape
the noexcept function) the program is terminated by a call to std::terminate(). The call
of terminate() cannot rely on objects being in well-defined states; that is, there is no guarantee
that destructors have been invoked, no guaranteed stack unwinding, and no possibility for resuming
the program as if no problem had been encountered. This is deliberate and makes noexcept a
simple, crude, and very efficient mechanism – much more efficient than the old
dynamic throw() exception specification mechanism.
It is possible to make a function conditionally noexcept. For example, an algorithm can be
specified to be noexcept if (and only if) the operations it uses on a template argument
are noexcept:
1. template<class T>
2. void do_f(vector<T>& v) noexcept(noexcept(f(v.at(0)))) // can throw if f(v.at(0)) can
3. {
4. for(int i; i<v.size(); ++i)
5. v.at(i) = f(v.at(i));
6. }
Here, we first use noexcept as an operator: noexcept(f(v.at(0))) is true
if f(v.at(0)) can’t throw, that is if the f() and at() used are noexcept.
The noexcept() operator is a constant expression and does not evaluate its operand.
The general form of a noexcept declaration is noexcept(expression) and “plain noexcept”
is simply a shorthand for noexcept(true). All declarations of a function must have
compatible noexcept specifications.
A destructor shouldn’t throw; a generated destructor is implicitly noexcept (independently of what
code is in its body) if all of the members of its class have noexcept destructors (which, ahem, they
too will have by default).
It is typically a bad idea to have a move operation throw, so declare those noexcept wherever
possible. A generated copy or move operation is implicitly noexcept if all of the copy or move
operations it uses on members of its class have noexcept destructors.
noexcept is widely and systematically used in the standard library to improve performance and
clarify requirements.
See also:
Standard: 15.4 Exception specifications [except.spec].
Standard: 5.3.7 noexcept operator [expr.unary.noexcept].
[N3103==10-0093] D. Kohlbrenner, D. Svoboda, and A. Wesie: Security impact of
noexcept. (Noexcept must terminate, as it does).
[N3167==10-0157] David Svoboda: Delete operators default to noexcept.
[N3204==10-0194] Jens Maurer: Deducing “noexcept” for destructors.
[N3050==10-0040] D. Abrahams, R. Sharoni, and D. Gregor: Allowing Move Constructors
to Throw (Rev. 1).
constexpr
The constexpr mechanism
provides more general constant expressions
allows constant expressions involving user-defined types
provides a way to guarantee that an initialization is done at compile time
Consider
1. enum Flags { good=0, fail=1, bad=2, eof=4 };
2.
3. constexpr int operator|(Flags f1, Flags f2) { return Flags(int(f1)|int(f2)); }
4.
5. void f(Flags x)
6. {
7. switch (x) {
8. case bad: /* ... */ break;
9. case eof: /* ... */ break;
10. case bad|eof: /* ... */ break;
11. default: /* ... */ break;
12. }
13. }
Here constexpr says that the function must be of a simple form so that it can be evaluated at
compile time if given constant expressions arguments.
In addition to be able to evaluate expressions at compile time, we want to be able to require
expressions to be evaluated at compile time; constexpr in front of a variable definition does that
(and implies const):
1. constexpr int x1 = bad|eof; // ok
2.
3. void f(Flags f3)
4. {
5. constexpr int x2 = bad|f3; // error: can't evaluate at compile time
6. int x3 = bad|f3; // ok
7. }
Typically we want the compile-time evaluation guarantee for global or namespace objects, often for
objects we want to place in read-only storage.
This also works for objects for which the constructors are simple enough to be constexpr and
expressions involving such objects:
1. struct Point {
2. int x,y;
3. constexpr Point(int xx, int yy) : x(xx), y(yy) { }
4. };
5.
6. constexpr Point origo(0,0);
7. constexpr int z = origo.x;
8.
9. constexpr Point a[] = {Point(0,0), Point(1,1), Point(2,2) };
10. constexpr int x = a[1].x; // x becomes 1
Please note that constexpr is not a general purpose replacement for const (or vice versa):
const’s primary function is to express the idea that an object is not modified through an
interface (even though the object may very well be modified through other interfaces). It just so
happens that declaring an object const provides excellent optimization opportunities for the
compiler. In particular, if an object is declared const and its address isn’t taken, a compiler is
often able to evaluate its initializer at compile time (though that’s not guaranteed) and keep that
object in its tables rather than emitting it into the generated code.
constexpr’s primary function is to extend the range of what can be computed at compile
time, making such computation type safe and also usable in compile-time contexts (such as to
initialize enumerator or integral template parameters). Objects declared constexpr have their
initializer evaluated at compile time; they are basically values kept in the compiler’s tables and
only emitted into the generated code if needed.
See also:
the C++ draft 3.6.2 Initialization of non-local objects, 3.9 Types [12], 5.19 Constant
expressions, 7.1.5 The constexpr specifier
[N1521=03-0104] Gabriel Dos Reis: Generalized Constant Expressions (original proposal).
[N2235=07-0095] Gabriel Dos Reis, Bjarne Stroustrup, and Jens Maurer: Generalized
Constant Expressions – Revision 5.
nullptr – a null pointer literal
nullptr is a literal denoting the null pointer; it is not an integer:
1. char* p = nullptr;
2. int* q = nullptr;
3. char* p2 = 0; // 0 still works and p==p2
4.
5. void f(int);
6. void f(char*);
7.
8. f(0); // call f(int)
9. f(nullptr); // call f(char*)
10.
11. void g(int);
12. g(nullptr); // error: nullptr is not an int
13. int i = nullptr; // error: nullptr is not an int
See also:
[N1488==/03-0071] Herb Sutter and Bjarne Stroustrup: A name for the null pointer: nullptr.
[N2214 = 07-0074 ] Herb Sutter and Bjarne Stroustrup: A name for the null pointer: nullptr
(revision 4).
ECMA-372 for a description of this feature as originally designed in C++/CLI before being
proposed for ISO C++.
Copying and rethrowing exceptions
How do you catch an exception and then rethrow it on another thread? Use a bit of library magic as
described in the standard 18.8.5 Exception Propagation:
exception_ptr current_exception(); Returns: An exception_ptr object that
refers to the currently handled exception (15.3) or a copy of the currently handled exception, or a
null exception_ptr object if no exception is being handled. The referenced object shall remain
valid at least as long as there is an exception_ptr object that refers to it. …
void rethrow_exception(exception_ptr p);
template<class E> exception_ptr copy_exception(E e); Effects: as if
1. try {
2. throw e;
3. } catch(...) {
4. return current_exception();
5. }
This is particularly useful for transmitting an exception from one thread to another.
Inline namespaces
The inline namespace mechanism is intended to support library evolution by providing a
mechanism that supports a form of versioning. Consider:
1. // file V99.h:
2. inline namespace V99 {
3. void f(int); // does something better than the V98 version
4. void f(double); // new feature
5. // ...
6. }
7.
8. // file V98.h:
9. namespace V98 {
10. void f(int); // does something
11. // ...
12. }
13.
14. // file Mine.h:
15. namespace Mine {
16. #include "V99.h"
17. #include "V98.h"
18. }
We here have a namespace Mine with both the latest release (V99) and the previous one (V98). If
you want to be specific, you can:
1. #include "Mine.h"
2. using namespace Mine;
3. // ...
4. V98::f(1); // old version
5. V99::f(1); // new version
6. f(1); // default version
The point is that the inline specifier makes the declarations from the nested namespace appear
exactly as if they had been declared in the enclosing namespace.
This is a very “static” and implementer-oriented facility in that the inline specifier has to be
placed by the designer of the namespaces – thus making the choice for all users. It is not possible for
a user of Mine to say “I want the default to be V98 rather than V99.”
See
Standard 7.3.1 Namespace definition [7]-[9].
User-defined literals
C++ has always provided literals for a variety of built-in types (2.14 Literals):
1. 123 // int
2. 1.2 // double
3. 1.2F // float
4. 'a' // char
5. 1ULL // unsigned long long
6. 0xD0 // hexadecimal unsigned
7. "as" // string
However, in C++98 there are no literals for user-defined types. This can be a bother and also seen as
a violation of the principle that user-defined types should be supported as well as built-in types are.
In particular, people have requested:
1. "Hi!"s // std::string, not ``zero-terminated array of char''
2. 1.2i // imaginary
3. 123.4567891234df // decimal floating point (IBM)
4. 101010111000101b // binary
5. 123s // seconds
6. 123.56km // not miles! (units)
7. 1234567890123456789012345678901234567890x // extended-precision
C++11 supports “user-defined literals” through the notion of literal operators that map literals with a
given suffix into a desired type. For example:
1. constexpr complex<double> operator "" i(long double d) // imaginary literal
2. {
3. return {0,d}; // complex is a literal type
4. }
5.
6. std::string operator""s (const char* p, size_t n) // std::string literal
7. {
8. return string(p,n); // requires free store allocation
9. }
Note the use of constexpr to enable compile-time evaluation. Given those, we can write
1. template<class T> void f(const T&);
2. f("Hello"); // pass pointer to char*
3. f("Hello"s); // pass (5-character) string object
4. f("Hello\n"s); // pass (6-character) string object
5.
6. auto z = 2+1i; // complex(2,1)
The basic (implementation) idea is that after parsing what could be a literal, the compiler always
checks for a suffix. The user-defined literal mechanism simply allows the user to specify a new
suffix and what is to be done with the literal before it. It is not possible to redefine the meaning of a
built-in literal suffix or augment the syntax of literals. A literal operator can request to get its
(preceding) literal passed “cooked” (with the value it would have had if the new suffix hadn’t been
defined) or “uncooked” (as a string).
To get an “uncooked” string, simply request a single const char* argument:
1. Bignum operator"" x(const char* p)
2. {
3. return Bignum(p);
4. }
5.
6. void f(Bignum);
7. f(1234567890123456789012345678901234567890x);
Here the C-style string "1234567890123456789012345678901234567890" is passed
to operator"" x(). Note that we did not explicitly put those digits into a string.
There are four kinds of literals that can be suffixed to make a user-defined literal.
Integer literal: accepted by a literal operator taking a single unsigned long
long or const char* argument.
Floating-point literal: accepted by a literal operator taking a single long double or const
char* argument.
String literal: accepted by a literal operator taking a pair of (const char*, size_t)
arguments.
Character literal: accepted by a literal operator taking a single char argument.
Note that you cannot make a literal operator for a string literal that takes just a const
char* argument (and no size). For example:
1. string operator"" S(const char* p); // warning: this will not work as expected
2.
3. "one two"S; // error: no applicable literal operator
The rationale is that if we want to have “a different kind of string” we almost always want to know
the number of characters anyway.
Suffixes will tend to be short (e.g. s for string, i for imaginary, m for meter, and x for extended),
so different uses could easily clash. Use namespaces to prevent clashes:
1. namespace Numerics {
2. // ...
3. class Bignum { /* ... */ };
4. namespace literals {
5. operator"" X(char const*);
6. }
7. }
8.
9. using namespace Numerics::literals;
See also:
Standard 2.14.8 User-defined literals
[N2378==07-0238] Ian McIntosh, Michael Wong, Raymond Mak, Robert Klarer, Jens
Mauer, Alisdair Meredith, Bjarne Stroustrup, David Vandevoorde: User-defined Literals (aka.
Extensible Literals (revision 3)).
enum class
long long – a longer integer
Extended integer types
Generalized unions
Generalized PODs
enum class
The enum classes (“new enums”, “strong enums”) address three problems with traditional C++
enumerations:
Conventional enums implicitly convert to an integer, causing errors when someone does not
want an enumeration to act as an integer.
Conventional enums export their enumerators to the surrounding scope, causing name
clashes.
The underlying type of an enum cannot be specified, causing confusion, compatibility
problems, and makes forward declaration impossible.
enum classes (“strong enums”) are strongly typed and scoped:
1. enum Alert { green, yellow, orange, red }; // traditional enum
2.
3. enum class Color { red, blue }; // scoped and strongly typed enum
4. // no export of enumerator names into enclosing scope
5. // no implicit conversion to int
6. enum class TrafficLight { red, yellow, green };
7.
8. Alert a = 7; // error (as ever in C++)
9. Color c = 7; // error: no int->Color conversion
10.
11. int a2 = red; // ok: Alert->int conversion
12. int a3 = Alert::red; // error in C++98; ok in C++11
13. int a4 = blue; // error: blue not in scope
14. int a5 = Color::blue; // error: not Color->int conversion
15.
16. Color a6 = Color::blue; // ok
As shown, traditional enums work as usual, but you can now optionally qualify enumerators with
the enum name
The new enums are “enum class” because they combine aspects of traditional enumerations
(names values) with aspects of classes (scoped members and absence of conversions). This is the
same name for this feature as when it was originally designed in C++/CLI before being proposed for
ISO C++.
Being able to specify the underlying type allows simpler interoperability and guaranteed sizes of
enumerations:
1. enum class Color : char { red, blue }; // compact representation
2.
3. enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int
4.
5. enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E?
6. // (whatever the old rules say;
7. // i.e. "implementation defined")
8.
9. enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific
It also enables forward declaration of enums:
1. enum class Color_code : char; // (forward) declaration
2. void foobar(Color_code* p); // use of forward declaration
3. // ...
4. enum class Color_code : char { red, yellow, green, blue }; // definition
The underlying type must be one of the signed or unsigned integer types; the default is int.
In the standard library, enum classes are used
For mapping systems specific error codes: In : enum class errc;
For pointer safety indicators: In : enum class pointer_safety { relaxed, preferred, strict };
For I/O stream errors: In : enum class io_errc { stream = 1 };
For asynchronous communications error handling: In : enum class future_errc
{ broken_promise, future_already_retrieved, promise_already_satisfied };
Several of these have operators such as == defined.
See also:
the C++ draft section 7.2
[N1513=03-0096] David E. Miller: Improving Enumeration Types (original enum proposal).
[N2347 = J16/07-0207] David E. Miller, Herb Sutter, and Bjarne Stroustrup: Strongly Typed
Enums (revision 3).
[N2499=08-0009] Alberto Ganesh Barbati: Forward declaration of enumerations.
long long – a longer integer
An integer that’s at least 64 bits long. For example:
1. long long x = 9223372036854775807LL;
No, there are no long long longs nor can long be spelled short long long.
See also:
[05-0071==N1811] J. Stephen Adamczyk: Adding the long long type to C++ (Revision
3).
Extended integer types
There is a set of rules for how an extended (precision) integer type should behave if one exists.
See
[06-0058==N1988] J. Stephen Adamczyk: Adding extended integer types to C++ (Revision
1).
Generalized unions
In C++98 (as in the earlier pre-Standard versions of C++), a member with a user-defined
constructor, destructor, or assignment cannot be a member of a union:
1. union U {
2. int m1;
3. complex<double> m2; // error (silly): complex has constructor
4. string m3; // error (not silly): string has a serious invariant
5. // maintained by ctor, copy, and dtor
6. };
In particular
1. U u; // which constructor, if any?
2. u.m1 = 1; // assign to int member
3. string s = u.m3; // disaster: read from string member
Obviously, it’s illegal to write one member and then read another but people do that nevertheless
(usually by mistake).
C++11 modifies the restrictions of unions to make more member types feasible; in particular, it
allows a member of types with constructors and destructors. It also adds a restriction to make the
more flexible unions less error-prone by encouraging the building of discriminated unions.
Union member types are restricted:
No virtual functions (as ever)
No references (as ever)
No bases (as ever)
If a union has a member with a user-defined constructor, copy, or destructor then that special
function is deleted; that is, it cannot be used for an object of the union type. This is new.
For example:
1. union U1 {
2. int m1;
3. complex<double> m2; // ok
4. };
5.
6. union U2 {
7. int m1;
8. string m3; // ok
9. };
This may look error-prone, but the new restriction helps. In particular:
1. U1 u; // ok
2. u.m2 = {1,2}; // ok: assign to the complex member
3. U2 u2; // error: the string destructor caused the U destructor to be deleted
4. U2 u3 = u2; // error: the string copy constructor caused the U copy constructor to be deleted
Basically, U2 is useless unless you embed it in a struct that keeps track of which member (variant) is
used. So, build discriminated unions, such as:
1. class Widget { // Three alternative implementations represented as a union
2. private:
3. enum class Tag { point, number, text } type; // discriminant
4. union { // representation
5. point p; // point has constructor
6. int i;
7. string s; // string has default constructor, copy operations, and destructor
8. };
9. // ...
10. widget& operator=(const widget& w) // necessary because of the string variant
11. {
12. if (type==Tag::text && w.type==Tag::text) {
13. s = w.s; // usual string assignment
14. return *this;
15. }
16.
17. if (type==Tag::text) s.~string(); // destroy (explicitly!)
18.
19. switch (w.type) {
20. case Tag::point: p = w.p; break; // normal copy
21. case Tag::number: i = w.i; break;
22. case Tag::text: new(&s)(w.s); break; // placement new
23. }
24. type = w.type;
25. return *this;
26. }
27. };
See also:
the C++ draft section 9.5
[N2544=08-0054] Alan Talbot, Lois Goldthwaite, Lawrence Crowl, and Jens
Maurer: Unrestricted unions (Revision 2)
Generalized PODs
A POD (“Plain Old Data”) is something that can be manipulated like a C struct, e.g. bitwise
copyable with memcpy(), bitwise initializable with memset(), etc. In C++98 the actual definition
of POD is based on a set of restrictions on the use of language features used in the definition of a
struct:
1. // S is a POD
2. struct S {
3. int a;
4. };
5.
6. // SS was not a POD in C++98, is a POD in C++11
7. struct SS {
8. int a;
9. SS(int aa) : a(abs(aa)) { assert(a>=0); }
10. };
11.
12. // Definitely not POD
13. struct SSS {
14. virtual void f(); /* ... */
15. };
In C++11, S and SS are “standard layout types” (a superset of “POD types”) because there is really
nothing “magic” about SS: The constructor does not affect the layout (so memcpy() would be fine),
only the initialization rules do (memset() would be bad – not enforcing any invariant the type
might have, such as a >= 0). However, SSS will still have an embedded vptr and will not be
anything like “plain old data.” C++11 defines POD types, trivially copyable types, trivial types,
and standard-layout types to deal with various technical aspects of what used to be PODs. POD is
defined recursively:
If all your members and bases are PODs, you’re a POD
As usual (details in section 9 [10])
No virtual functions
No virtual bases
No references
No multiple access specifiers
The most important aspect of C++11 PODs is that adding or subtracting constructors do not affect
layout or performance.
See also:
the C++ draft section 3.9 and 9 [10]
[N2294=07-0154] Beman Dawes: POD’s Revisited; Resolving Core Issue 568 (Revision 4).
Extern templates
Template aliases
Variadic templates
Local types as template arguments
Extern templates
A template specialization can be explicitly declared as a way to suppress multiple instantiations. For
example:
1. #include "MyVector.h"
2.
3. extern template class MyVector<int>; // Suppresses implicit instantiation below --
4. // MyVector<int> will be explicitly instantiated elsewhere
5.
6. void foo(MyVector<int>& v)
7. {
8. // use the vector in here
9. }
The “elsewhere” might look something like this:
1. #include "MyVector.h"
2.
3. template class MyVector<int>; // Make MyVector available to clients (e.g., of the shared library
This is basically a way of avoiding significant redundant work by the compiler and linker.
See:
Standard 14.7.2 Explicit instantiation
[N1448==03-0031] Mat Marcus and Gabriel Dos Reis: Controlling Implicit Template
Instantiation.
Template aliases
How can we make a template that’s “just like another template” but possibly with a couple of
template arguments specified (bound)? Consider:
1. template<class T>
2. using Vec = std::vector<T,My_alloc<T>>; // standard vector using my allocator
3.
4. Vec<int> fib = { 1, 2, 3, 5, 8, 13 }; // allocates elements using My_alloc
5.
6. vector<int,My_alloc<int>> verbose = fib; // verbose and fib are of the same type
The keyword using is used to get a linear notation “name followed by what it refers to.” We tried
with the conventional and convoluted typedef solution, but never managed to get a complete and
coherent solution until we settled on a less obscure syntax.
Specialization works (you can alias a set of specializations but you cannot specialize an alias) For
example:
1. template<int>
2. struct int_exact_traits { // idea: int_exact_trait<N>::type is a type with exactly N bits
3. typedef int type;
4. };
5.
6. template<>
7. struct int_exact_traits<8> {
8. typedef char type;
9. };
10.
11. template<>
12. struct int_exact_traits<16> {
13. typedef char[2] type;
14. };
15.
16. // ...
17.
18. template<int N>
19. using int_exact = typename int_exact_traits<N>::type; // define alias for convenient notation
20.
21. int_exact<8> a = 7; // int_exact<8> is an int with 8 bits
In addition to being important in connection with templates, type aliases can also be used as a
different (and IMO better) syntax for ordinary type aliases:
1. typedef void (*PFD)(double); // C style
2. using PF = void (*)(double); // using plus C-style type
3. using P = auto (*)(double)->void; // using plus suffix return type
See also:
the C++ draft: 14.6.7 Template aliases; 7.1.3 The typedef specifier
[N1489=03-0072] Bjarne Stroustrup and Gabriel Dos Reis: Templates aliases for C++.
[N2258=07-0118] Gabriel Dos Reis and Bjarne Stroustrup: Templates Aliases (Revision
3) (final proposal).
Variadic templates
Problems to be solved:
How to construct a class with 1, 2, 3, 4, 5, 6, 7, 8, 9, or … initializers?
How to avoid constructing an object out of parts and then copying the result?
How to construct a tuple?
The last question is the key: Think tuple! If you can make and access general tuples the rest will
follow.
Here is an example (from “A brief introduction to Variadic templates” (see references))
implementing a general, type-safe, printf(). It would probably be better to use boost::format,
but consider:
1. const string pi = "pi";
2. const char* m = "The value of %s is about %g (unless you live in %s).\n";
3. printf(m, pi, 3.14159, "Indiana");
The simplest case of printf() is when there are no arguments except the format string, so we’ll
handle that first:
1. void printf(const char* s)
2. {
3. while (s && *s) {
4. if (*s=='%' && *++s!='%') // make sure that there wasn't meant to be more arguments
5. // %% represents plain % in a format string
6. throw runtime_error("invalid format: missing arguments");
7. std::cout << *s++;
8. }
9. }
That done, we must handle printf() with more arguments:
1. template<typename T, typename... Args> // note the "..."
2. void printf(const char* s, T value, Args... args) // note the "..."
3. {
4. while (s && *s) {
5. if (*s=='%' && *++s!='%') { // a format specifier (ignore which one it is)
6. std::cout << value; // use first non-format argument
7. return printf(++s, args...); // "peel off" first argument
8. }
9. std::cout << *s++;
10. }
11. throw std::runtime error("extra arguments provided to printf");
12. }
This code simply “peels off” the first non-format argument and then calls itself recursively. When
there are no more non-format arguments, it calls the first (simpler) printf() (above). This is
rather standard functional programming done at compile time. Note how the overloading
of << replaces the use of the (possibly erroneous) “hint” in the format specifier.
The Args... defines what is called a “parameter pack.” That’s basically a sequence of (type/value)
pairs from which you can “peel off” arguments starting with the first. When printf() is called
with one argument, the first printf(const char*) is chosen. When printf() is called with
two or more arguments, the second printf(const char*, T value, Args... args)) is
chosen, with the first argument as s, the second as value, and the rest (if any) bundled into the
parameter pack args for later use. In the call
1. printf(++s, args...);
the parameter pack args is expanded so that the next argument can now be selected as value. This
carries on until args is empty (so that the first printf() is called).
If you are familiar with functional programming, you should find this an unusual notation for a
pretty standard technique. If not, here are some small technical examples that might help. First we
can declare and use a simple variadic template function (just like printf() above):
1. template<class ... Types>
2. void f(Types ... args); // variadic template function
3. // (i.e. a function that can take an arbitrary number of arguments of arbitrary types)
4. f(); // OK: args contains no arguments
5. f(1); // OK: args contains one argument: int
6. f(2, 1.0); // OK: args contains two arguments: int and double
We can build a variadic type:
1. template<typename Head, typename... Tail>
2. class tuple<Head, Tail...>
3. : private tuple<Tail...> { // here is the recursion
4. // Basically, a tuple stores its head (first (type/value) pair
5. // and derives from the tuple of its tail (the rest of the (type/value) pairs.
6. // Note that the type is encoded in the type, not stored as data
7. typedef tuple<Tail...> inherited;
8. public:
9. tuple() { } // default: the empty tuple
10.
11. // Construct tuple from separate arguments:
12. tuple(typename add_const_reference<Head>::type v, typename add_const_reference<Tail>::type...
vtail)
13. : m_head(v), inherited(vtail...) { }
14.
15. // Construct tuple from another tuple:
16. template<typename... VValues>
17. tuple(const tuple<VValues...>& other)
18. : m_head(other.head()), inherited(other.tail()) { }
19.
20. template<typename... VValues>
21. tuple& operator=(const tuple<VValues...>& other) // assignment
22. {
23. m_head = other.head();
24. tail() = other.tail();
25. return *this;
26. }
27.
28. typename add_reference<Head>::type head() { return m_head; }
29. typename add_reference<const Head>::type head() const { return m_head; }
30.
31. inherited& tail() { return *this; }
32. const inherited& tail() const { return *this; }
33. protected:
34. Head m_head;
35. }
Given that definition, we can make tuples (and copy and manipulate them):
1. tuple<string,vector,double> tt("hello",{1,2,3,4},1.2);
2. string h = tt.head(); // "hello"
3. tuple<vector<int>,double> t2 = tt.tail(); // {{1,2,3,4},1.2};
It can get a bit tedious to mention all of those types, so often, we deduce them from argument types,
e.g. using the standard library make_tuple():
1. template<class... Types>
2. tuple<Types...> make_tuple(Types&&... t) // this definition is somewhat simplified (see standard
20.5.2.2)
3. {
4. return tuple<Types...>(t...);
5. }
6.
7. string s = "Hello";
8. vector<int> v = {1,22,3,4,5};
9. auto x = make_tuple(s,v,1.2);
See also:
Standard 14.6.3 Variadic templates
[N2151==07-0011] D. Gregor, J. Jarvi: Variadic Templates for the C++0x Standard Library.
[N2080==06-0150] D. Gregor, J. Jarvi, G. Powell: Variadic Templates (Revision 3).
[N2087==06-0157] Douglas Gregor: A Brief Introduction to Variadic Templates.
[N2772==08-0282] L. Joly, R. Klarer: Variadic functions: Variadic templates or initializer
lists? – Revision 1.
[N2551==08-0061] Sylvain Pion: A Variadic std::min(T, ...) for the C++ Standard
Library (Revision 2).
Anthony Williams: An Introduction to Variadic Templates in C++0x. DevX.com, May 2009.
Local types as template arguments
In C++98, local and unnamed types could not be used as template arguments. This could be a
burden, so C++11 lifts the restriction:
1. void f(vector<X>& v)
2. {
3. struct Less {
4. bool operator()(const X& a, const X& b) { return a.v<b.v; }
5. };
6. sort(v.begin(), v.end(), Less()); // C++98: error: Less is local
7. // C++11: ok
8. }
In C++11, we also have the alternative of using a lambda expression:
1. void f(vector<X>& v)
2. {
3. sort(v.begin(), v.end(),
4. [] (const X& a, const X& b) { return a.v<b.v; }); // C++11
5. }
It is worth remembering that naming action can be quite useful for documentation and an
encouragement to good design. Also, non-local (necessarily named) entities can be reused.
C++11 also allows values of unnamed types to be used as template arguments:
1. template<typename T> void foo(T const& t){}
2. enum X { x };
3. enum { y };
4.
5. int main()
6. {
7. foo(x); // C++98: ok; C++11: ok
8. foo(y); // C++98: error; C++11: ok
9. enum Z { z };
10. foo(z); // C++98: error; C++11: ok
11. }
See also:
[N2402=07-0262] Anthony Williams: Names, Linkage, and Templates (rev 2).
[N2657] John Spicer: Local and Unnamed Types as Template Arguments.
unique_ptr
shared_ptr
weak_ptr
Garbage collection ABI
tuple
Type traits
function and bind
Regular Expressions
Time utilities
Random number generation
Scoped allocators
unique_ptr
unique_ptr (defined in <memory>) provides a semantics of strict ownership:
owns the object it holds a pointer to
is not CopyConstructible, nor CopyAssignable, however it is MoveConstructible and
MoveAssignable.
stores a pointer to an object and deletes that object using the associated deleter when it is
itself destroyed (such as when leaving block scope (6.7)).
The uses of unique_ptr include:
providing exception safety for dynamically allocated memory
passing ownership of dynamically allocated memory to a function
returning dynamically allocated memory from a function
storing pointers in containers
unique_ptr is almost exactly as efficient as using a raw pointer, but with safe ownership
semantics. It’s “what auto_ptr should have been” (but that we couldn’t write in C++98).
unique_ptr is a move-only type, and so relies critically on rvalue references and move semantics.
Here is a conventional 20th-century piece of exception unsafe code:
1. X* f()
2. {
3. X* p = new X;
4. // do something - maybe throw an exception
5. return p;
6. }
A solution is to hold the pointer to the object on the free store in a unique_ptr:
1. X* f()
2. {
3. unique_ptr<X> p(new X); // or {new X} but not = new X
4. // do something -- maybe throw an exception
5. return p.release();
6. }
Now, if an exception is thrown, the unique_ptr will (implicitly) destroy the object pointed to.
That’s basic RAII. However, unless we really need to return a built-in pointer, we can do even better
by returning a unique_ptr:
1. unique_ptr<X> f()
2. {
3. unique_ptr<X> p(new X); // or {new X} but not = new X
4. // do something -- maybe throw an exception
5. return p; // the ownership is transferred out of f()
6. }
We can use this f like this:
1. void g()
2. {
3. unique_ptr<X> q = f(); // move using move constructor
4. q->memfct(2); // use q
5. X x = *q; // copy the object pointed to
6. // ...
7. } // q and the object it owns is destroyed on exit
The unique_ptr has “move semantics” so the initialization of q with the rvalue that is the result of
the call f() simply transfers ownership into q.
One of the uses of unique_ptr is as a pointer in a container that owns its heap-allocated objects,
where in the past we might have used a built-in pointer except for exception safety problems (and to
guarantee destruction of the pointed to elements):
1. vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} };
unique_ptr is represented by a simple built-in pointer and the overhead of using one compared to
a built-in pointer are miniscule. In particular, unique_ptr does not offer any form of dynamic
checking.
See also:
the C++ draft section 20.7.10
Howard E. Hinnant: unique_ptr Emulation for C++03 Compilers.
shared_ptr
A shared_ptr is used to represent shared ownership; that is, when two pieces of code need access
to some data but neither has exclusive ownership (in the sense of being responsible for destroying
the object). A shared_ptr is a reference counted pointer where the object pointed to is deleted
when the use count goes to zero. Here is a highly artificial example:
1. void test()
2. {
3. shared_ptr<int> p1(new int); // count is 1
4. {
5. shared_ptr<int> p2(p1); // count is 2
6. {
7. shared_ptr<int> p3(p1); // count is 3
8. } // count goes back down to 2
9. } // count goes back down to 1
10. } // here the count goes to 0 and the int is deleted.
A more realistic example would be be pointers to nodes in a general graph where someone wanting
to remove a pointer to a node wouldn’t know if anyone else held a pointer to that node. If a node
can hold resources that require an action by a destructor (e.g. a file handle so that a file needs to be
closed when the node is deleted). You could consider shared_ptr to be for what you might
consider plugging in a garbage collector for, except that maybe you don’t have enough garbage for
that to be economical, your execution environment doesn’t allow that, or the resource managed is
not just memory (e.g. that file handle) so that you need release to be deterministic when the last user
goes away instead of done lazily at some nondeterminstic time, and ordered so that the object’s
destructor can safely use other heap objects. For example:
1. struct Node { // note: a Node may be pointed to from several other nodes.
2. shared_ptr<Node> left;
3. shared_ptr<Node> right;
4. File_handle f;
5. // ...
6. };
Here Node’s destructor (the implicitly generated destructor will do fine) deletes its sub-nodes; that
is, left and right’s destructors are invoked. When this node is destroyed, since left is
a shared_ptr, the Node pointed to (if any) is deleted if left was the last pointer to it; right is
handled similarly and f’s destructor does whatever is required for f.
Note that you should not use a shared_ptr just to pass a pointer from one owner to another; that’s
what unique_ptr is for and unique_ptr does that cheaper and better. If you have been using
counted pointers as return values from factory functions and the like, consider upgrading
to unique_ptr rather than shared_ptr.
Please don’t thoughtlessly replace pointers with shared_ptrs in an attempt to prevent memory
leaks; shared_ptrs are not a panacea nor are they without costs:
a circular linked structure of shared_ptrs will cause a memory leak (you’ll need some
logical complication to break the circle, e.g. using a weak_ptr),
“shared ownership objects” tend to stay “live” for longer than scoped objects (thus causing
higher average resource usage),
heavy manipulation of shared pointers themselves (such as transferring ownership around
frequently, though this is an antipattern) can be expensive in a multi-threaded environment
because of the need to avoid data races on the use count,
the algorithms/logic for the update of any shared object is easier to get wrong than for an
object that’s not shared.
A shared_ptr represents shared ownership but shared ownership isn’t always ideal: By default, it
is better if an object has a definite owner and a definite, predictable lifespan. Prefer the following in
order: stack or member lifetime (stack variables or by-value member variables); heap allocation
with unique_ptr unique ownership; and heap allocation via make_shared with shared
ownership.
See also:
the C++ draft: Shared_ptr (20.7.13.3)
Herb Sutter: GotW #89: Smart Pointers.
Herb Sutter: GotW #90: Factories.
Herb Sutter: GotW #91: Smart Pointer Parameters.
weak_ptr
weak_ptrs are for shared observation just as shared_ptrs are for shared ownership. weak_ptrs
are commonly known to be what you need to break cycles in data structures managed
using shared_ptrs, but more generally it is better to think of a weak_ptr as a pointer to
something that
1. you need access to (only) if it exists, and
2. may get deleted (by someone else), and
3. must have its destructor called after its last use (usually to delete a non-memory resource)
Consider an implementation of the old “asteroid game”. All asteroids are owned by “the game” but
each asteroids must keep track of neighboring asteroids and handle collisions. A collision typically
leads to the destruction of one or more asteroids. Each asteroid must keep a list of other asteroids in
its neighborhood. Note that being on such a neighbor list should not keep an astroid “alive” (so
a shared_ptr would be inappropriate). On the other hand, an asteroid must not be destroyed while
another asteroid is looking at it (e.g. to calculate the effect of a collision). And obviously, an
asteroid’s destructor must be called to release resources (such as a connection to the graphics
system). What we need is a list of asteroids that might still be intact and a way of “getting hold of
one if it exists” for a while. A weak_ptr does just that:
1. void owner()
2. {
3. // ...
4. vector<shared_ptr<Asteroid>> va(100);
5. for (int i=0; i<va.size(); ++i) {
6. // ... calculate neighbors for new asteroid ...
7. va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]));
8. launch(i);
9. }
10. // ...
11. }
reset() is the function to make a shared_ptr refer to a new object.
Obviously, this example code radically simplified “the owner” and gave each new Asteroid just
one neighbor. The key is that we give the Asteroid a weak_ptr to that neighbor. The owner
keeps a shared_ptr to represent the ownership that’s shared whenever an Asteroid is looking
(but not otherwise). The collision calculation for an Asteroid will look something like this:
1. void collision(weak_ptr<Asteroid> p)
2. {
3. if (auto q = p.lock()) { // p.lock returns a shared_ptr to p's object
4. // ... that Asteroid still existed: calculate ...
5. }
6. else {
7. // ... oops: that Asteroid has already been destroyed: just forget about it (delete the weak_ptr to
it ...
8. }
9. }
Note that even if the owner decides to shut down the game and deletes all Asteroids (by
destroying the shared_ptrs representing ownership), every Asteroid that is in the middle of
calculating a collision still finishes correctly because after the p.lock() it holds
a shared_ptr that will ensure the Asteroid stays alive for at least as long as collision is
using it via that shared_ptr.
You should expect to find weak_ptr use much rarer than “plain” shared_ptr use, and both of
those to be rarer than unique_ptr which should be most popular of all as it represents a simpler
(and more efficient) notion of ownership and (therefore) allows better local reasoning.
See also:
the C++ draft: weak_ptr (20.7.13.3)
Garbage collection ABI
Garbage collection (automatic recycling of unreferenced regions of memory) is optional in C++;
that is, a garbage collector is not a compulsory part of an implementation. However, C++11
provides a definition of what a GC can do if one is used and an ABI (Application Binary Interface)
to help control its actions.
The rules for pointers and lifetimes are expressed in terms of “safely derived pointer” (3.7.4.3);
roughly: “pointer to something allocated by new or to a sub-object thereof.” Here are some
examples of “not safely derived pointers” aka “disguised pointers” aka what not to do in a program
you want to be considered well behaved and comprehensible to ordinary mortals:
Make a pointer point “elsewhere” for a while
1. int* p = new int;
2. p+=10;
3. // ... collector may run here ...
4. p-=10;
5. *p = 10; // can we be sure that the int is still there?
Hide the pointer in an int
1. int* p = new int;
2. int x = reinterpret_cast<int>(p); // non-portable
3. p=0;
4. // ... collector may run here ...
5. p = reinterpret_cast<int*>(x);
6. *p = 10; // can we be sure that the int is still there?
There are many more and even nastier tricks. Think I/O, think “scattering the bits around in
different words”, …
There are legitimate reasons to disguise pointers (e.g. the xor trick in exceptionally memory-
constrained applications), but not as many as some programmers think.
A programmer can specify where there are no pointers to be found (e.g. inside a JPEG image) and
what memory can’t be reclaimed even if the collector can’t find a pointer into it:
1. void declare_reachable(void* p); // the region of memory starting at p
2. // (and allocated by some allocator
3. // operation which remembers its size)
4. // must not be collected
5. template<class T> T* undeclare_reachable(T* p);
6.
7. void declare_no_pointers(char* p, size_t n); // p[0..n] holds no pointers
8. void undeclare_no_pointers(char* p, size_t n);
A programmer can inquire which rules for pointer safety and reclamation is in force:
1. enum class pointer_safety {relaxed, preferred, strict };
2. pointer_safety get_pointer_safety();
3.7.4.3[4]: If a pointer value that is not a safely-derived pointer value is dereferenced or deallocated,
and the referenced complete object is of dynamic storage duration and has not previously been
declared reachable (20.7.13.7), the behavior is undefined.
relaxed: safely-derived and not safely-derived pointers are treated equivalently; like C and
C++98, but that was not my intent - I wanted to allow GC if a user didn’t keep a valid pointer
around for an object.
preferred: like relaxed; but a garbage collector may be running as a leak detector and/or
detector of dereferences of “bad pointers”
strict: safely-derived and not safely-derived pointers may be treated differently, i.e. a garbage
collector may be running and will ignore pointers that aren’t safely derived
There is no standard way of saying which alternative you prefer. Considered that a “quality of
implementation” and a “programming environment” issue.
See also:
the C++ draft 3.7.4.3
the C++ draft 20.7.13.7
Hans Boehm’s GC page
Hans Boehm’s Discussion of Conservative GC
N2527: Hans-J. Boehm and Mike Spertus: Minimal Support for Garbage Collection and
Reachability-Based Leak Detection (revised) (final proposal)
Michael Spertus and Hans J. Boehm: The Status of Garbage Collection in C++0X. ACM
ISMM’09.
tuple
The standard library tuple (an N-tuple) is a ordered sequence of N values where N can be a
constant from 0 to a large implementation-defined value, defined in <tuple>. You can think of
a tuple as an unnamed struct with members of the specified element types. In particular, the
elements of a tuple are stored compactly; a tuple is not a linked structure.
The element types of a tuple can explicitly specified or be deduced (using make_tuple()) and
the elements can be access by (zero-based) index using get():
1. tuple<string,int> t2("Kylling",123);
2.
3. auto t = make_tuple(string("Herring"),10, 1.23); // t will be of type tuple<string,int,double>
4. string s = get<0>(t);
5. int x = get<1>(t);
6. double d = get<2>(t);
Tuples are used (directly of indirectly) whenever we want a heterogeneous list of elements at
compile time but do not want to define a named class to hold them. For example, tuple is used
internally in std::function and std::bind to hold arguments.
The most frequently useful tuple is the 2-tuple; that is, a pair. However, pair is directly
supported in the standard library through std::pair (20.3.3 Pairs). A pair can be used to
initialize a tuple, but the opposite isn’t the case.
The comparison operators (==, !=, <, <=, >, and >=) are defined for tuples of comparable element
types.
See also:
Standard: 20.5.2 Class template tuple
[N2087==06-0157] Douglas Gregor: A Brief Introduction to Variadic Templates.
Boost::tuple
Type traits
See:
[N2984==09-0174] B. Dawes, D. Krügler, A. Meredith: Additional Type Traits for C++0x
(Revision 1).
function and bind
Note: function is long-term useful. However, bind is almost entirely superseded by C++14
lambdas with generalized lambda capture, but it has a few advantages if your compiler supports
only C++11 lambdas and can be more compact in basic cases.
The bind and function standard function objects are defined in <functional> (together with a
lot of other function objects); they are used to handle functions and function arguments. bind is
used to take a function (or a function object or anything you can invoke using the (a,b,c) syntax)
and produce a function object with one or more of the arguments of the argument function “bound”
or rearranged. For example:
1. int f(int,char,double);
2.
3. auto ff = bind(f,_1,'c',1.2); // deduce return type
4. int x = ff(7); // f(7,'c',1.2);
5.
6. // equivalent with lambdas
7. auto ff2 = [](int i){ f(i,'c',1.2); }; // deduce return type
8. int x2 = ff2(7); // f(7,'c',1.2);
This binding of arguments is usually called “Currying.” The _1 is a placeholder object indicating
where the first argument of ff is to go when f is called through ff. The first argument is called _1,
the second _2, and so on. For example:
1. int f(int,char,double);
2.
3. auto frev = bind(f,_3,_2,_1); // reverse argument order
4. int x = frev(1.2,'c',7); // f(7,'c',1.2);
5.
6. // equivalent with lambdas
7. auto frev2 = [](double d, char c, int i){ f(i,c,d); }; // reverse argument order
8. int x2 = frev2(1.2,'c',7); // f(7,'c',1.2);
Note how auto saves us from having to specify the type of the result of bind.
If the function to be called is overloaded, it is not possible to just bind arguments. Instead, we have
to explicitly state which version of an overloaded function we want to bind:
1. int g(int);
2. double g(double); // g() is overloaded
3.
4. auto g1 = bind(g,_1); // error: which g()?
5. auto g2 = bind((double(*)(double))g,_1); // ok (but ugly)
6.
7. // equivalent with C++11 lambdas, which handle this naturally
8. auto g3 = [](double d){ g(d); }; // ok in C++11
9.
10. // both shorter and more powerful with C++14 lambdas
11. auto g4 = [](auto x){ g(x); }; // ok in C++14, and gives full access to the overload set
bind() comes in two variants: the one shown above and a “legacy” version where you explicitly
specify the return type:
1. auto f2 = bind<int>(f,7,'c',_1); // explicit return type
2. int x = f2(1.2); // f(7,'c',1.2);
This second version was necessary in C++98 and is widely used because the first (and for a user
simplest) version cannot be implemented in C++98.
function is a type that can hold a value of just about anything you can invoke using
the (a,b,c) syntax, including allowing conversions on the parameters and the return type, making
it a very flexible facility indeed while preserving strict type-safety. In particular, the result
of bind can be assigned to a function. function is very simple to use. For example:
1. function<float (int x, int y)> f; // make a function object
2.
3. struct int_div { // take something you can call using ()
4. float operator()(int x, int y) const { return ((float)x)/y; };
5. };
6.
7. f = int_div(); // assign
8. cout << f(5, 3) << endl; // call through the function object
9. std::accumulate(b,e,1,f); // passes beautifully
Member functions can be treated as free functions with an extra “explicit this” argument:
1. struct X {
2. int foo(int);
3. };
4.
5. function<int (X*, int)> f;
6. f = &X::foo; // pointer to member
7.
8. X x;
9. int v = f(&x, 5); // call X::foo() for x with 5
10. function<int (int)> ff = std::bind(f,&x,_1); // first argument for f is &x
11. v=ff(5); // call x.foo(5)
functions are useful for callbacks, for passing operations as argument, etc. function can be seen
as a replacement for the C++98 standard library function
objects mem_fun_t, pointer_to_unary_function, etc. Similarly, bind() can be seen as a
replacement for bind1st() and bind2nd().
See also:
Standard: 20.7.12 Function template bind, 20.7.16.2 Class template function
Herb Sutter: Generalized Function Pointers. August 2003.
Douglas Gregor: Boost.Function.
Boost::bind
Regular Expressions
To be written.
In the meantime, see:
Microsoft documentation.
Time utilities
We often want to time things or to do things dependent on timing. For example, the standard-
library mutexes and locks provide the option for a thread to wait for a period of time (a duration)
or to wait until a given point in time (a time_point).
If you want to know the current time_point, you can call now() for one of three
clocks: system_clock, steady_clock, and high_resolution_clock. For example:
1. steady_clock::time_point t = steady_clock::now();
2. // do something
3. steady_clock::duration d = steady_clock::now() - t;
4. // something took d time units
A clock returns a time_point, and a duration is the difference between two time_points from
the same clock. As usual, if you are not interested in details, auto is your friend:
1. auto t = steady_clock::now();
2. // do something
3. auto d = steady_clock::now() - t;
4. // something took d time units
The time facilities here are intended to efficiently support uses deep in the system; they do not
provide convenience facilities to help you maintain your social calendar. In fact, the time facilities
originated with the stringent needs for high-energy physics. To be able to express all time scales
(such as centuries and picoseconds), avoid confusion about units, typos, and rounding
errors, durations and time_points are expressed using a compile-time rational number package.
A duration has two parts: a numeric clock “tick” and something (a “period”) that says what a tick
means (is it a second or a millisecond?); the period is part of a duration’s type. The following
table from the standard header <ratio>, defining the periods of the SI system (also known as MKS
or metric system) might give you an idea of the scope of use:
1. // convenience SI typedefs:
2. typedef ratio<1, 1000000000000000000000000> yocto; // conditionally supported
3. typedef ratio<1, 1000000000000000000000> zepto; // conditionally supported
4. typedef ratio<1, 1000000000000000000> atto;
5. typedef ratio<1, 1000000000000000> femto;
6. typedef ratio<1, 1000000000000> pico;
7. typedef ratio<1, 1000000000> nano;
8. typedef ratio<1, 1000000> micro;
9. typedef ratio<1, 1000> milli;
10. typedef ratio<1, 100> centi;
11. typedef ratio<1, 10> deci;
12. typedef ratio< 10, 1> deca;
13. typedef ratio< 100, 1> hecto;
14. typedef ratio< 1000, 1> kilo;
15. typedef ratio< 1000000, 1> mega;
16. typedef ratio< 1000000000, 1> giga;
17. typedef ratio< 1000000000000, 1> tera;
18. typedef ratio< 1000000000000000, 1> peta;
19. typedef ratio< 1000000000000000000, 1> exa;
20. typedef ratio< 1000000000000000000000, 1> zetta; // conditionally supported
21. typedef ratio<1000000000000000000000000, 1> yotta; // conditionally supported
The compile time rational numbers provide the usual arithmetic (+, -, *, and /) and comparison
(==, !=, <, <=, >, >=) operators for whatever combinations durations and time_points makes
sense (e.g. you can’t add two time_points). These operations are also checked for overflow and
divide by zero. Since this is a compile-time facility, don’t worry about run-time performance. In
addition you can use ++, --, +=, -=, *=, and /= on durations and tp+=d and tp-=d for
a time_point tp and a duration d.
Here are some examples of values using standard duration types as defined in <chrono>:
1. microseconds mms = 12345;
2. milliseconds ms = 123;
3. seconds s = 10;
4. minutes m = 30;
5. hours h = 34;
6.
7. auto x = std::chrono::hours(3); // being explicit about namespaces
8. auto x = hours(2)+minutes(35)+seconds(9); // assuming suitable "using"
You cannot initialize a duration to a fraction. For example, don’t try 2.5 seconds; instead use
2500 milliseconds. This is because a duration is interpreted as a number of “ticks.” Each tick
represents one unit of the duration’s “period,” such as milli and kilo as defined above. The
default unit is seconds; that is, for a duration with a period of 1 a tick is interpreted as a second. We
can be explicit about the representation of a duration:
1. duration<long> d0 = 5; // seconds (by default)
2. duration<long,kilo> d1 = 99; // kiloseconds!
3. duration<long,ratio<1000,1>> d2 = 100; // d1 and d2 have the same type ("kilo" means "*1000")
If we actually want to do something with a duration, such as writing it out, we have to give a unit,
such as minutes or microseconds. For example:
1. auto t = steady_clock::now();
2. // do something
3. nanoseconds d = steady_clock::now() - t; // we want the result in nanoseconds
4. cout << "something took " << d << "nanoseconds\n";
Alternatively, we could convert the duration to a floating point number (to get rounding):
1. auto t = steady_clock::now();
2. // do something
3. auto d = steady_clock::now() - t;
4. cout << "something took " << duration_cast<double>(d).count() << "seconds\n";
The count() is the number of “ticks.”“
See also:
Standard: 20.9 Time utilities [time]
Howard E. Hinnant, Walter E. Brown, Jeff Garland, and Marc Paterno: A Foundation to
Sleep On. N2661=08-0171. Including “A Brief History of Time” (With apologies to Stephen
Hawking).
Random number generation
Random numbers are useful in many contexts, such as testing, games, simulation, and security. The
diversity of application areas is reflected in the wide selection of random number generation utilities
provided by the standard library. A random number generator consists of two parts: (1) an engine
that produces a sequence of random or pseudo-random values, and (2) a distribution that maps those
values to a mathematical distribution in a range. Examples of distributions
are uniform_int_distribution (where all integers produced are equally likely)
and normal_distribution (“the bell curve”), each for some specified range. For example:
1. uniform_int_distribution<int> one_to_six {1,6}; // distribution that maps to the ints 1..6
2. default_random_engine re {}; // the default engine
To get a random number, you call a distribution with an engine:
1. int x = one_to_six(re); // x becomes a value in [1:6]
To avoid passing the engine in every call, we could bind that argument to get a function object
that’s callable without arguments:
1. auto dice {bind(one_to_six,re)}; // make a generator
2.
3. int x = dice(); // roll the dice: x becomes a value in [1:6]
(Thanks to its uncompromising attention to generality and performance, one expert deemed the
standard-library random number component “what every random number library wants to be when
it grows up.)
What if we just want something simple to use like:
1. int rand_int(int low, int high); // generate a random number from a uniform distribution in
[low:high]
So, how could we get that? We have to put something like dice() inside rand_int():
1. int rand_int(int low, int high)
2. {
3. static default_random_engine re {};
4. using Dist = uniform_int_distribution<int>;
5. static Dist uid {};
6. return uid(re, Dist::param_type{low,high});
7. }
While providing that definition needs a bit of expertise, calling rand_int() is manageable in even
the first week of a C++ course.
Just to show a non-trivial example, here is a program that generates and prints a normal
distribution’s histogram:
1.
#include <iostream>
2. #include <random>
3. #include <vector>
4.
5. std::default_random_engine re; // the default engine
6. std::normal_distribution<double> nd(31 /* mean */, 8 /* sigma */);
7.
8. auto norm = std::bind(nd, re);
9.
10. std::vector<int> mn(64);
11.
12. int main()
13. {
14. for (int i = 0; i<1200; ++i) ++mn[round(norm())]; // generate
15.
16. for (int i = 0; i<mn.size(); ++i) {
17. std::cout << i << '\t';
18. for (int j=0; j<mn[i]; ++j) std::cout << '*';
19. std::cout << '\n';
20. }
21. }
The result of one execution was:
1. 0
2. 1
3. 2
4. 3
5. 4 *
6. 5
7. 6
8. 7
9. 8
10. 9 *
11. 10 ***
12. 11 ***
13. 12 ***
14. 13 *****
15. 14 *******
16. 15 ****
17. 16 **********
18. 17 ***********
19. 18 ****************
20. 19 *******************
21. 20 *******************
22. 21 **************************
23. 22 **********************************
24. 23 **********************************************
25. 24 ********************************************
26. 25 *****************************************
27. 26 *********************************************
28. 27 *********************************************************
29. 28 ***************************************************
30. 29 ******************************************************************
31. 30 **********************************************
32. 31 *********************************************************************
33. 32 **********************************************
34. 33 *************************************************************
35. 34 **************************************************************
36. 35 ***************************************
37. 36 ***********************************************
38. 37 **********************************************
39. 38 *********************************************
40. 39 ********************************
41. 40 ********************************************
42. 41 ***********************
43. 42 **************************
44. 43 ******************************
45. 44 *****************
46. 45 *************
47. 46 *********
48. 47 ********
49. 48 *****
50. 49 *****
51. 50 ****
52. 51 ***
53. 52 ***
54. 53 **
55. 54 *
56. 55 *
57. 56
58. 57 *
59. 58
60. 59
61. 60
62. 61
63. 62
64. 63
See also:
Standard 26.5: Random number generation
Walter E. Brown: Random Number Generation in C++11 – note, normally committee papers
are not tutorials, and it’s not often you get an excellent tutorial written by a world-class expert
who is also the designer of the library – strongly recommended as a go-to source of information
about <random>
Scoped allocators
For compactness of container objects and for simplicity, C++98 did not require containers to
support allocators with state: Allocator objects need not be stored in container objects. This is still
the default in C++11, but it is possible to use an allocator with state, say an allocator that holds a
pointer to an arena from which to allocate. For example:
1. template<class T> class Simple_alloc { // C++98 style
2. // no data
3. // usual allocator stuff
4. };
5.
6. class Arena {
7. void* p;
8. int s;
9. public:
10. Arena(void* pp, int ss);
11. // allocate from p[0..ss-1]
12. };
13.
14. template<class T> struct My_alloc {
15. Arena& a;
16. My_alloc(Arena& aa) : a(aa) { }
17. // usual allocator stuff
18. };
19.
20. Arena my_arena1(new char[100000],100000);
21. Arena my_arena2(new char[1000000],1000000);
22.
23. vector<int> v0; // allocate using default allocator
24.
25. vector<int,My_alloc<int>> v1(My_alloc<int>{my_arena1}); // allocate from my_arena1
26.
27. vector<int,My_alloc<int>> v2(My_alloc<int>{my_arena2}); // allocate from my_arena2
28.
29. vector<int,Simple_alloc<int>> v3; // allocate using Simple_alloc
Typically, the verbosity would be alleviated by the use of typedefs.
It is not guaranteed that the default allocator and Simple_alloc take up no space in
a vector object, but a bit of elegant template metaprogramming in the library implementation can
ensure that. So, using an allocator type imposes a space overhead only if its objects actually has
state (like My_alloc).
A rather sneaky problem can occur when using containers and user-defined allocators: Should an
element be in the same allocation area as its container? For example, if you
use Your_alloc for Your_string to allocate its elements and someone else uses My_alloc to
allocate elements of My_vector, then which allocator should be used for string elements
in My_vector<Your_alloc>>? The solution is the ability to tell a container which allocator to
pass to elements. For example, assuming that there is an allocator My_alloc and you want
a vector<string> that uses My_alloc for both the vector element and string element
allocations, first, you must make a version of string that accepts My_alloc objects:
1. using xstring = basic_string<char, char_traits<char>, My_alloc<char>>; // a string with my allocator
Then, you must make a version of vector that accepts those strings, accepts a My_alloc object,
and passes that object on to the string:
1. using svec = vector<xstring,scoped_allocator_adaptor<My_alloc<xstring>>>;
Finally, we can make an allocator of type My_alloc<xstring>:
1. svec v(svec::allocator_type(My_alloc<xstring>{my_arena1}));
Now svec is a vector of strings using My_alloc to allocate memory for strings. What’s new is
that the standard library “adaptor” (“wrapper type”) scoped_allocator_adaptor is used to
indicate that string also should use My_alloc. Note that the adaptor can (trivially)
convert My_alloc<xstring> to the My_alloc<char> that string needs.
So, we have four alternatives:
1. // vector and string use their own (the default) allocator:
2. using svec0 = vector<string>;
3. svec0 v0;
4.
5. // vector (only) uses My_alloc and string uses its own (the default) allocator:
6. using svec1 = vector<string,My_alloc<string>>;
7. svec1 v1(My_alloc<string>{my_arena1});
8.
9. // vector and string use My_alloc (as above):
10. using xstring = basic_string<char, char_traits<char>, My_alloc<char>>;
11. using svec2 = vector<xstring,scoped_allocator_adaptor<My_alloc<xstring>>>;
12. svec2 v2(scoped_allocator_adaptor<My_alloc<xstring>>{my_arena1});
13.
14. // vector uses My_alloc and string uses My_string_alloc:
15. using xstring2 = basic_string<char, char_traits<char>, My_string_alloc<char>>;
16. using svec3 = vector<xstring2,scoped_allocator_adaptor<My_alloc<xstring>, My_string_alloc<char>>>;
17. svec3 v3(scoped_allocator_adaptor<My_alloc<xstring2>,
My_string_alloc<char>>{my_arena1,my_string_arena});
Obviously, the first variant, svec0, will be by far the most common, but for systems with serious
memory-related performance constraints, the other versions (especially svec2) can be important. A
few typedefs would make that code a bit more readable, but it is good it is not something you
have to write every day. The scoped_allocator_adaptor2 is a variant
of scoped_allocator_adaptor for the case where the two non-default allocators differ.
See also:
Standard: 20.8.5 Scoped allocator adaptor [allocator.adaptor]
Pablo Halpern: The Scoped Allocator Model (Rev 2). N2554=08-0064.
Algorithms improvements
Container improvements
unordered_* containers
std::array
forward_list
Algorithms improvements
The standard library algorithms are improved partly by simple addition of new algorithms, partly by
improved implementations made possible by new language features, and partly by new language
features enabling easier use:
New algorithms:
1. bool all_of(Iter first, Iter last, Pred pred);
2. bool any_of(Iter first, Iter last, Pred pred);
3. bool none_of(Iter first, Iter last, Pred pred);
4.
5. Iter find_if_not(Iter first, Iter last, Pred pred);
6.
7. OutIter copy_if(InIter first, InIter last, OutIter result, Pred pred);
8. OutIter copy_n(InIter first, InIter::difference_type n, OutIter result);
9.
10. OutIter move(InIter first, InIter last, OutIter result);
11. OutIter move_backward(InIter first, InIter last, OutIter result);
12.
13. pair<OutIter1, OutIter2> partition_copy(InIter first, InIter last, OutIter1 out_true, OutIter2 out_false,
Pred pred);
14. Iter partition_point(Iter first, Iter last, Pred pred);
15.
16. RAIter partial_sort_copy(InIter first, InIter last, RAIter result_first, RAIter result_last);
17. RAIter partial_sort_copy(InIter first, InIter last, RAIter result_first, RAIter result_last, Compare
comp);
18. bool is_sorted(Iter first, Iter last);
19. bool is_sorted(Iter first, Iter last, Compare comp);
20. Iter is_sorted_until(Iter first, Iter last);
21. Iter is_sorted_until(Iter first, Iter last, Compare comp);
22.
23. bool is_heap(Iter first, Iter last);
24. bool is_heap(Iter first, Iter last, Compare comp);
25. Iter is_heap_until(Iter first, Iter last);
26. Iter is_heap_until(Iter first, Iter last, Compare comp);
27.
28. T min(initializer_list<T> t);
29. T min(initializer_list<T> t, Compare comp);
30. T max(initializer_list<T> t);
31. T max(initializer_list<T> t, Compare comp);
32. pair<const T&, const T&> minmax(const T& a, const T& b);
33. pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp);
34. pair<const T&, const T&> minmax(initializer_list<T> t);
35. pair<const T&, const T&> minmax(initializer_list<T> t, Compare comp);
36. pair<Iter, Iter> minmax_element(Iter first, Iter last);
37. pair<Iter, Iter> minmax_element(Iter first, Iter last, Compare comp);
38.
39. void iota(Iter first, Iter last, T value); // For each element referred to by the iterator i in the range
[first,last), assigns *i = value and increments value as if by ++value
Effects of move: Moving can be much more efficient than copying (see Move semantics. For
example, move-based std::sort() and std::set::insert() have been measured to be 15
times faster than copy based versions. This is less impressive than it sounds because such standard
library operations for standard library types, such as string and vector, are usually hand-
optimized to gain the effects of moving through techniques such as replacing copies with
optimized swaps. However, if your type has a move operation, you gain the performance benefits
automatically from the standard algorithms. Consider also that the use of moves allows simple
and efficient sort (and other algorithms) of containers of smart pointers, especially unique_ptr:
1. template<class P> struct Cmp<P> { // compare *P values
2. bool operator() (P a, P b) const { return *a<*b; }
3. }
4.
5. vector<std::unique_ptr<Big>> vb;
6. // fill vb with unique_ptr's to Big objects
7.
8. sort(vb.begin(),vb.end(),Cmp<Big>()); // don't try that with an auto_ptr
Use of lambdas: For ages, people have complained about having to write functions or (better)
function objects for use as operations, such as Cmp<T> above, for standard library (and other)
algorithms. This was especially painful to do if you wrote large functions (don’t) because in C+
+98 you could not define a local function object to use as an argument; now you can.
However, lambdas allows us to define operations “inline”:
1. sort(vb.begin(),vb.end(),[](unique_ptr<Big> a, unique_ptr<Big> b) { return *a<*b; });
Use of initializer lists: Sometimes, initializer lists come in handy as arguments. For example,
assuming string variables and Nocase being a case-insensitive comparison:
1. auto x = max({x,y,z},Nocase());
See also:
25 Algorithms library [algorithms]
26.7 Generalized numeric operations [numeric.ops]
Howard E. Hinnant, Peter Dimov, and Dave Abrahams: A Proposal to Add Move Semantics
Support to the C++ Language. N1377=02-0035.
Container improvements
Given the new language features and a decade’s worth of experience, what has happened to the
standard containers? First, of course we got a few new ones: array (a fixed-sized
container), forward_list (a singly-linked list), and unordered containers (the hash tables). Next, new
features, such as initializer lists, rvalue references, variadic templates, and constexpr[cpp11-
constexpr] were put to use. Consider std::vector.
Initializer lists: The most visible improvement is the use of initializer-list constructors to
allow a container to take an initializer list as its argument:
1. vector<string> vs = { "Hello", ", ", "World!", "\n" };
2. for (auto s : vs ) cout << s;
Move operators: Containers now have move constructors and move assignments (in addition
to the traditional copy operations). The most important implication of this is that we can
efficiently return a container by value from a function:
1. vector<int> make_random(int n)
2. {
3. vector<int> ref(n);
4. for(auto& x : ref) x = rand_int(0,255); // some random number generator
5. return ref;
6. }
7.
8. vector<int> v = make_random(10000);
9. for (auto x : make_random(1000000)) cout << x << '\n';
The point here is that no vectors are copied. Rewrite this to return a free-store-allocated vector and
you have to deal with memory management. Rewrite this to pass the vector to be filled as an
argument to make_random() and you have a far less obvious code (plus an added opportunity for
making an error).
Improved push operations: Many people’s favorite container operation is push_back() that
allows a container to grow gracefully:
1. vector<pair<string,int>> vp;
2. string s;
3. int i;
4. while(cin>>s>>i) vp.push_back({s,i});
This will construct a pair<string,int> out of s and i and move it into vp. Note “move” not
“copy;” there is a push_back version that takes an rvalue reference argument so that we can take
advantage of string’s move constructor. Note also the use of the uniform initializer syntax to
avoid verbosity.
Emplace operations: The push_back() using a move constructor is far more efficient in
important cases than the traditional copy-based one, but in extreme cases we can go further. Why
copy/move anything? Why not make space in the vector and then construct the desired value in
that space? Operations that do that are called “emplace” (meaning “putting in place”). For
example emplace_back():
1. vector<pair<string,int>> vp;
2. string s;
3. int i;
4. while(cin>>s>>i) vp.emplace_back(s,i);
An emplace takes a variadic template argument and uses that to construct an object of the desired
type. Whether the emplace_back() really is more efficient than the push_back() depends on
the types involved and the implementation (of the library and of variadic templates). If you think it
matters, measure. Otherwise, choose based on
aesthetics: vp.push_back({s,i}); or vp.emplace_back(s,i);. For now, many prefer
the push_back() version in part due to familiarity, but that might change over time.
Scoped allocators: Containers can now hold “real allocation objects (with state)” and use
those to control nested/scoped allocation (e.g. allocation of elements in a container).
Obviously, the containers are not the only parts of the standard library that have benefited from the
new language features. Consider:
Compile-time evaluation: constexpr is used to ensure compiler time evaluation
in <numeric_limits>, bitset, duration, char_traits, array, atomic types, random
numbers, complex, etc. In some cases, it means improved performance; in others (where there is
no alternative to compile-time evaluation), it means absence of messy low-level code and macros.
Tuples: Tuples would not be possible without variadic templates
unordered_* containers
An unordered_* container is implemented using a hash table. C++11 offers four standard ones:
unordered_map
unordered_set
unordered_multimap
unordered_multiset
They would have been called hash_map etc., but there are so many incompatible uses of those
names that the committee had to choose new names and the unordered_* name nicely
highlighted the key difference between (say) map and unordered_map: When you iterate over
a map from begin() to end(), you do so in the order provided by its key type’s less-than
comparison operator (by default <) whereas the value type of unordered_map is not required to
have a less-than comparison operator and a hash table doesn’t naturally provide an order. The are
other differences; in particular, conversely, the element type of a map is not required to have a hash
function.
The basic idea is simply to use unordered_map as an optimized version of map where
optimization is possible and reasonable. For example:
1. map<string,int> m {
2. {"Dijkstra",1972}, {"Scott",1976}, {"Wilkes",1967}, {"Hamming",1968}
3. };
4. m["Ritchie"] = 1983;
5. for(auto& x : m) cout << '{' << x.first << ',' << x.second << '}';
6.
7. unordered_map<string,int> um {
8. {"Dijkstra",1972}, {"Scott",1976}, {"Wilkes",1967}, {"Hamming",1968}
9. };
10. um["Ritchie"] = 1983;
11. for(auto& x : um) cout << '{' << x.first << ',' << x.second << '}';
The iterator over m will present the elements in alphabetical order; the iteration over um will not
(except through a freak accident). Lookup is implemented very differently for m and um.
For m lookup involves log2(m.size()) less-than comparisons, whereas for um lookup involves a
single call of a hash function and one or more equality operations. For a few elements (say a few
dozen), it is hard to tell which is faster. For larger numbers of elements (e.g. thousands), lookup in
an unordered_map can be much faster than for a map.
See also:
Standard: 23.5 Unordered associative containers.
std::array
The standard container array is a fixed-sized random-access sequence of elements defined
in <array>. It has no space overheads beyond what it needs to hold its elements, it does not use
free store, it can be initialized with an initializer list, it knows its size (number of elements), and
doesn’t convert to a pointer unless you explicitly ask it to. In other words, it is very much like a
built-in array without the problems.
1. array<int,6> a = { 1, 2, 3 };
2. a[3]=4;
3. int x = a[5]; // x becomes 0 because default elements are zero initialized
4. int* p1 = a; // error: std::array doesn't implicitly convert to a pointer
5. int* p2 = a.data(); // ok: get pointer to first element
Note that you can have zero-length arrays but that you cannot deduce the length of an array from
an initializer list:
1. array<int> a3 = { 1, 2, 3 }; // error: size unknown/missing
2. array<int,0> a0; // ok: no elements
3. int* p = a0.data(); // unspecified; don't try it
The standard array’s features makes it attractive for embedded systems programming (and similar
constrained, performance-critical, or safety critical tasks). It is a sequence container so it provides
the usual member types and functions (just like vector):
1. template<class C> typename C::value_type sum(const C& a)
2. {
3. return accumulate(a.begin(),a.end(),0);
4. }
5.
6. array<int,10> a10;
7. array<double,1000> a1000;
8. vector<int> v;
9. // ...
10. int x1 = sum(a10);
11. double x2 = sum(a1000);
12. int x3 = sum(v);
Also, you don’t get (potentially nasty) derived to base conversions:
1. struct Apple : Fruit { /* ... */ };
2. struct Pear : Fruit { /* ... */ };
3.
4. void nasty(array<Fruit*,10>& f)
5. {
6. f[7] = new Pear();
7. };
8.
9. array<Apple*,10> apples;
10. // ...
11. nasty(apples); // error: can't convert array<Apple*,10> to array<Fruit*,10>;
If that was allowed, apples would now contain a Pear.
See also:
Standard: 23.3.1 Class template array
forward_list
The standard container forward_list, defined in <forward_list>, is basically a singly-linked
list. It supports forward iteration (only) and guarantees that elements don’t move if you insert or
erase one. It occupies minimal space (an empty list is likely to be one word) and does not provide
a size() operation (so that it does not have to store a size member):
1. template <ValueType T, Allocator Alloc = allocator<T> >
2. // requires NothrowDestructible<T>
3. class forward_list {
4. public:
5. // the usual container stuff
6. // no size()
7. // no reverse iteration
8. // no back() or push_back()
9. };
See also:
Standard: 23.3.3 Class template forward_list
Threads
Mutual exclusion
Locks
Condition variables
Atomics
Futures and promises
async
Abandoning a process
Threads
A thread is a representation of an execution/computation in a program. In C++11, as in much
modern computing, a thread can – and usually does – share an address space with other threads. In
this, it differs from a process, which generally does not directly share data with other processes. C+
+ has had a host of threads implementations for a variety of hardware and operating systems in the
past, what’s new is a standard-library threads library.
Many thick books and tens of thousands of papers have been written about concurrency,
parallelism, and threading, this FAQ entry barely scratches the surface. It is hard to think clearly
about concurrency. If you want to do concurrent programming, at least read a book. Do not rely just
on a manual, a standard, or a FAQ.
A thread is launched by constructing a std::thread with a function or a function object (incl.
a lambda):
1. #include <thread>
2.
3. void f();
4.
5. struct F {
6. void operator()();
7. };
8.
9. int main()
10. {
11. std::thread t1{f}; // f() executes in separate thread
12. std::thread t2{F()}; // F()() executes in separate thread
13. }
Unfortunately, this is unlikely to give any useful results – whatever f() and F() might do. The
snag is that the program may terminate before or after t1 executes f() and before or
after t2 executes F(). We need to wait for the two tasks to complete:
1. int main()
2. {
3. std::thread t1{f}; // f() executes in separate thread
4. std::thread t2{F()}; // F()() executes in separate thread
5.
6. t1.join(); // wait for t1
7. t2.join(); // wait for t2
8. }
The join()s ensure that we don’t terminate until the threads have completed. To “join” means to
wait for the thread to terminate.
Typically, we’d like to pass some arguments to the task to be executed (here we are calling
something executed by a thread a “task”). For example:
1. void f(vector<double>&);
2.
3. struct F {
4. vector<double>& v;
5. F(vector<double>& vv) :v{vv} { }
6. void operator()();
7. };
8.
9. int main()
10. {
11. std::thread t1{std::bind(f,some_vec)}; // f(some_vec) executes in separate thread
12. std::thread t2{F(some_vec)}; // F(some_vec)() executes in separate thread
13.
14. t1.join();
15. t2.join();
16. }
Basically, the standard library bind makes a function object of its arguments.
In general, we’d also like to get a result back from an executed task. With plain tasks, there is no
notion of a return value; std::future is the correct default choice for that. Alternatively, we can
pass an argument to a task telling it where to put its result: For example:
1. void f(vector<double>&, double* res); // place result in res
2.
3. struct F {
4. vector<double>& v;
5. double* res;
6. F(vector<double>& vv, double* p) :v{vv}, res{p} { }
7. void operator()(); // place result in res
8. };
9.
10. int main()
11. {
12. double res1;
13. double res2;
14.
15. std::thread t1{std::bind(f,some_vec,&res1)}; // f(some_vec,&res1) executes in separate thread
16. std::thread t2{F(some_vec,&res2)}; // F(some_vec,&res2)() executes in separate thread
17.
18. t1.join();
19. t2.join();
20.
21. std::cout << res1 << ' ' << res2 << '\n';
22. }
But what about errors? What if a task throws an exception? If a task throws an exception and
doesn’t catch it itself std::terminate() is called. That typically means that the program
finishes. We usually try rather hard to avoid that. A std::future can transmit an exception to the
parent/calling thread; that’s one reason to like futures. Otherwise, return some sort of error code.
When a thread goes out of scope the program is terminate()d unless its task has completed.
That’s obviously to be avoided.
There is no way to request a thread to terminate (i.e. request that it exit as a soon as possible and as
gracefully as possible) or to force a thread to terminate (i.e. kill it). We are left with the options of
designing our own cooperative “interruption mechanism” (with a piece of shared data that a
caller thread can set for a called thread to check, and quickly and gracefully exit when it is set),
“going native” by using thread::native_handle() to gain access to the operating
system’s notion of a thread,
kill the process (std::quick_exit()),
kill the program (std::terminate()).
This was all the committee could agree upon. In particular, representatives from POSIX were
vehemently against any form of “thread cancellation” however much C++’s model of resources rely
on destructors. There is no perfect solution for every system and every possible application.
The basic problem with threads is data races; that is, two threads running in a single address space
can independently access an object in ways that cause undefined results. If one (or both) writes to
the object and the other (or both) reads the object they have a “race” for who gets its operation(s)
done first. The results are not just undefined; they are usually completely unpredictable.
Consequently, C++11 provides some rules/guarantees for the programmer to avoid data races:
A C++ standard library function shall not directly or indirectly access objects accessible by
threads other than the current thread unless the objects are accessed directly or indirectly via the
function’s arguments, including this.
A C++ standard library function shall not directly or indirectly modify objects accessible by
threads other than the current thread unless the objects are accessed directly or indirectly via the
function’s nonconst arguments, including this.
C++ standard library implementations are required to avoid data races when different
elements in the same sequence are modified concurrently.
Concurrent access to a stream object, stream buffer object, or C Library stream by multiple threads
may result in a data race unless otherwise specified. So don’t share an output stream between two
threads unless you somehow control the access to it.
You can:
wait for a thread for a specified time
control access to some data by mutual exclusion
control access to some data using locks
wait for an action of another task using a condition variable
return a value from a thread through a future
See also:
Standard: 30 Thread support library [thread]
17.6.4.7 Data race avoidance [res.on.data.races]
H. Hinnant, L. Crowl, B. Dawes, A. Williams, J. Garland, et al.: Multi-threading Library for
Standard C++ (Revision 1) N2497==08-0007
H.-J. Boehm, L. Crowl: C++ object lifetime interactions with the threads API N2880==09-
0070.
L. Crowl, P. Plauger, N. Stoughton: Thread Unsafe Standard Functions N2864==09-0054.
WG14: Thread Cancellation N2455=070325.
Mutual exclusion
A mutex is a primitive object used for controlling access in a multi-threaded system. The most
basic use is:
1. std::mutex m;
2. int sh; // shared data
3. // ...
4. m.lock();
5. // manipulate shared data:
6. sh+=1;
7. m.unlock();
Only one thread at a time can be in the region of code between the lock() and
the unlock() (often called a critical region). If a second thread tries m.lock() while a first thread
is executing in that region, that second thread is blocked until the first executes the m.unlock().
This is simple. What is not simple is to use mutexes in a way that doesn’t cause serious problems:
What if a thread “forgets” to unlock()? What if a thread tries to lock() the same mutex twice?
What if a thread waits a very long time before doing an unlock()? What if a thread needs
to lock() two mutexes to do its job? The complete answers fill books. Here (and in the Locks
section) are just the raw basics.
In addition to lock(), a mutex has a try_lock() operation which can be used to try to get into
the critical region without the risk of getting blocked:
1. std::mutex m;
2. int sh; // shared data
3. // ...
4. if (m.try_lock()) {
5. // manipulate shared data:
6. sh+=1;
7. m.unlock();
8. else {
9. // maybe do something else
10. }
A recursive_mutex is a mutex that can be acquired more than once by a thread:
1. std::recursive_mutex m;
2. int sh; // shared data
3. // ...
4. void f(int i)
5. {
6. // ...
7. m.lock();
8. // manipulate shared data:
9. sh+=1;
10. if (--i>0) f(i);
11. m.unlock();
12. // ...
13. }
Here, we have been blatant and let f() call itself. Typically, the code is more subtle. The recursive
call will be indirect along the line of f() calls g() that calls h() that calls f().
What if you need to acquire a mutex within the next ten seconds? The timed_mutex class is
offered for that. Its operations are specialized versions of try_lock() with an associated time
limit:
1. std::timed_mutex m;
2. int sh; // shared data
3. // ...
4. if (m.try_lock_for(std::chrono::seconds(10))) {
5. // manipulate shared data:
6. sh+=1;
7. m.unlock();
8. }
9. else {
10. // we didn't get the mutex; do something else
11. }
The try_lock_for() takes a relative time, a duration as its argument. If instead you want to wait
until a fixed point in time, a time_point you can use try_lock_until():
1. std::timed_mutex m;
2. int sh; // shared data
3. // ...
4. if (m.try_lock_until(midnight)) {
5. // manipulate shared data:
6. sh+=1;
7. m.unlock();
8. }
9. else {
10. // we didn't get the mutex; do something else
11. }
The midnight is a feeble joke: For a mechanism as low level as mutexes, the timescale is more
likely to be milliseconds than hours.
There is of course also a recursive_timed_mutex.
A mutex is considered a resource (as it is typically used to represent a real resource) and must be
visible to at least two threads to be useful. Consequently, it cannot be copied or moved (you
couldn’t just make another copy of a hardware input register).
It can be surprisingly difficult to get the lock()s and unlock()s to match. Think of complicated
control structures, errors, and exceptions. If you have a choice, use locks to manage your mutexes;
that will save you and your users a lot of sleep.
See also:
Standard: 30.4 Mutual exclusion [thread.mutex]
H. Hinnant, L. Crowl, B. Dawes, A. Williams, J. Garland, et al.: Multi-threading Library for
Standard C++ (Revision 1)
Locks
A lock is an object that can hold a reference to a mutex and may unlock() the mutex during the
lock’s destruction (such as when leaving block scope). A thread may use a lock to aid in managing
mutex ownership in an exception safe manner. In other words, a lock implements Resource
Acquisition Is Initialization for mutual exclusion. For example:
1. std::mutex m;
2. int sh; // shared data
3. // ...
4. void f()
5. {
6. // ...
7. std::unique_lock lck(m);
8. // manipulate shared data: lock will be released even if this code throws an exception
9. sh+=1;
10. }
A lock can be moved (the purpose of a lock is to represent local ownership of a non-local resource),
but not copied (which copy would own the resource/mutex?).
This straightforward picture of a lock is clouded by unique_lock having facilities to do just about
everything a mutex can, but safer. For example, we can use a unique_lock to do try_lock:
1. std::mutex m;
2. int sh; // shared data
3. // ...
4. void f()
5. {
6. // ...
7. std::unique_lock lck(m,std::defer_lock); // make a lock, but don't acquire the mutex
8. // ...
9. if (lck.try_lock()) {
10. // manipulate shared data:
11. sh+=1;
12. }
13. else {
14. // maybe do something else
15. }
16. }
Similarly, unique_lock supports try_lock_for() and try_lock_until(). What you get
from using a lock rather than the mutex directly is exception handling and protection against
forgetting to unlock(). In concurrent programming, we need all the help we can get.
What if we need two resources represented by two mutexes? The naive way is to acquire the
mutexes in order:
1. std::mutex m1;
2. std::mutex m2;
3. int sh1; // shared data
4. int sh2
5. // ...
6. void f()
7. {
8. // ...
9. std::unique_lock lck1(m1);
10. std::unique_lock lck2(m2);
11. // manipulate shared data:
12. sh1+=sh2;
13. }
This has the potentially deadly flaw that some other thread could try to acquire m1 and m2 in the
opposite order so that each had one of the locks needed to proceed and would wait forever for the
second (that’s one classic form of deadlock). With many locks in a system, that’s a real danger.
Consequently, the standard locks provide two functions for (safely) trying to acquire two or more
locks:
1. void f()
2. {
3. // ...
4. std::unique_lock lck1(m1,std::defer_lock); // make locks but don't yet try to acquire the mutexes
5. std::unique_lock lck2(m2,std::defer_lock);
6. std::unique_lock lck3(m3,std::defer_lock);
7. lock(lck1,lck2,lck3);
8. // manipulate shared data
9. }
Obviously, the implementation of lock() has to be carefully crafted to avoid deadlock. In essence,
it will do the equivalent to careful use of try_lock()s. If lock() fails to acquire all locks it will
throw an exception. Actually, lock() can take any argument with lock(), try_lock(),
and unlock() member functions (e.g. a mutex), so we can’t be specific about which
exception lock() might throw; that depends on its arguments.
If you prefer to use try_lock()s yourself, there is an equivalent to lock() to help:
1. void f()
2. {
3. // ...
4. std::unique_lock lck1(m1,std::defer_lock); // make locks but don't yet try to acquire the mutexes
5. std::unique_lock lck2(m2,std::defer_lock);
6. std::unique_lock lck3(m3,std::defer_lock);
7. int x;
8. if ((x = try_lock(lck1,lck2,lck3))==-1) { // welcome to C land
9. // manipulate shared data
10. }
11. else {
12. // x holds the index of a mutex we could not acquire
13. // e.g. if lck2.try_lock() failed x==1
14. }
15. }
See also:
Standard: 30.4.3 Locks [thread.lock]
Condition variables
Condition variables provide synchronization primitives used to block a thread until notified by some
other thread that some condition is met or until a system time is reached.
See also:
Standard: 30.5 Condition variables [thread.condition]
Atomics
To be written.
In the meantime, see:
Herb Sutter: atomic<> Weapons: The C++ Memory Model and Modern Hardware, Part
1, Part 2, Slides, from C++ and Beyond, August 2012.
Futures and promises
Concurrent programming can be hard, especially if you try to be clever with threads, and locks. It is
harder still if you must use condition variables or use atomics (for lock-free programming). C++11
offers future and promise for returning a value from a task spawned on a separate thread,
and packaged_task to help launch tasks. The important point about future and promise is that
they enable a transfer of a value between two tasks without explicit use of a lock; “the system”
implements the transfer efficiently. The basic idea is simple: When a task wants to return a value to
the thread that launched it, it puts the value into a promise. Somehow, the implementation makes
that value appear in the future attached to the promise. The caller (typically the launcher of the
task) can then read the value. For added simplicity, see async().
The standard provides three kinds of futures, future for most simple uses,
and shared_future and atomic_future for some trickier cases. Here, we’ll just
present future because it’s the simplest and does all we need done. If we have
a future<X> called f, we can get() a value of type X from it:
1. X v = f.get(); // if necessary wait for the value to get computed
If the value isn’t there yet, our thread is blocked until it arrives. If the value couldn’t be computed
and the task threw an exception, calling get() will rethrow that exception to the code
calling get().
We might not want to wait for a result, so we can ask the future if a result has arrived:
1. if (f.wait_for(0)) { // there is a value to get()
2. // do something
3. }
4. else {
5. // do something else
6. }
However, the main purpose of future is to provide that simple get().
The main purpose of promise is to provide a simple set() to match future’s get(). The
names future and promise are historical; they are also a fertile source of puns.
If you have a promise and need to send a result of type X (back) to a future, there are basically two
things you can do: pass a value and pass an exception:
1. try {
2. X res;
3. // compute a value for res
4. p.set_value(res);
5. }
6. catch (...) { // oops: couldn't compute res
7. p.set_exception(std::current_exception());
8. }
So far so good, but how do I get a matching future/promise pair, one in my thread and one in
some other thread? Well, since futures and promises can be moved (not copied) around there is a
wide variety of possibilities. The most obvious idea is for whoever wants a task done to create a
thread and give the promise to it while keeping the corresponding future as the place for the result.
Using async() is the most extreme/elegant variant of the latter technique.
The packaged_task type is provided to simplify launching a thread to execute a task. In
particular, it takes care of setting up a future connected to a promise and to provides the wrapper
code to put the return value or exception from the task into the promise. For example:
1. double comp(vector<double>& v)
2. {
3. // package the tasks:
4. // (the task here is the standard accumulate() for an array of doubles):
5. packaged_task<double(double*,double*,double)> pt0{std::accumulate<double*,double*,double>};
6. packaged_task<double(double*,double*,double)> pt1{std::accumulate<double*,double*,double>};
7.
8. auto f0 = pt0.get_future(); // get hold of the futures
9. auto f1 = pt1.get_future();
10.
11. pt0(&v[0],&v[v.size()/2],0); // start the threads
12. pt1(&v[v.size()/2],&v[size()],0);
13.
14. return f0.get()+f1.get(); // get the results
15. }
See also:
Standard: 30.6 Futures [futures]
Anthony Williams: Moving Futures - Proposed Wording for UK comments 335, 336, 337
and 338. N2888==09-0078.
Detlef Vollmann, Howard Hinnant, and Anthony Williams: An Asynchronous Future Value
(revised) N2627=08-0137.
Howard E. Hinnant: Multithreading API for C++0X – A Layered Approach. N2094=06-
0164. The original proposal for a complete threading package.
async
Here is an example of a way for the programmer to rise above the messy threads-plus-lock level of
concurrent programming:
1. template<class T, class V> struct Accum { // simple accumulator function object
2. T* b;
3. T* e;
4. V val;
5. Accum(T* bb, T* ee, const V& v) : b{bb}, e{ee}, val{vv} {}
6. V operator() () { return std::accumulate(b,e,val); }
7. };
8.
9. double comp(vector<double>& v)
10. // spawn many tasks if v is large enough
11. {
12. if (v.size()<10000) return std::accumulate(v.begin(),v.end(),0.0);
13.
14. auto f0 {async(Accum{&v[0],&v[v.size()/4],0.0})};
15. auto f1 {async(Accum{&v[v.size()/4],&v[v.size()/2],0.0})};
16. auto f2 {async(Accum{&v[v.size()/2],&v[v.size()*3/4],0.0})};
17. auto f3 {async(Accum{&v[v.size()*3/4],&v[v.size()],0.0})};
18.
19. return f0.get()+f1.get()+f2.get()+f3.get();
20. }
This is a very simple-minded use of concurrency (note the “magic number”), but note the absence of
explicit threads, locks, buffers, etc. The type of the f-variables are determined by the return type of
the standard-library function async() which is a future. If necessary, get() on a future waits
for a thread to finish. Here, it is async()’s job to spawn threads as needed and the future’s job
to join() the threads appropriately. “Simple” is the most important aspect of
the async()/future design; futures can also be used with threads in general, but don’t even think
of using async() to launch tasks that do I/O, manipulate mutexes, or in other ways interact with
other tasks. The idea behind async() is the same as the idea behind the range-for statement:
Provide a simple way to handle the simplest, rather common, case and leave the more complex
examples to the fully general mechanism.
An async() can be requested to launch in a new thread, in any thread but the caller’s, or to launch
in a different thread only if async() “thinks” that it is a good idea. The latter is the simplest from
the user’s perspective and potentially the most efficient (for simple tasks only).
The committee is actively working on providing a much more general form of executors (execution
agents) that will subsume std::async. In the meantime, std::async is the simple facility
included in the standard.
See also:
Lawrence Crowl: An Asynchronous Call for C++. N2889 = 09-0079.
Herb Sutter : A simple async() N2901 = 09-0091 .
Abandoning a process
To be written.
In the meantime, see:
Lawrence Crowl: Abandoning a Process. N2440, 2007.
C++14 Overview
Save to:
InstapaperPocketReadability
Contents of this section:
What is C++14?
C++14 is the ISO C++ standard formally ratified by a national vote in 2014. This public working
paper is the October 2013 working draft, and contains the C++14 draft standard which is expected
to be finalized with a few more minor tweaks and editorial changes.
C++14 is a minor but important upgrade over C++11, and largely “completes C++11.”
Binary literals
Generalized return type deduction
decltype(auto)
Generalized lambda captures
Generic lambdas
Variable templates
Extended constexpr
The [ [deprecated] ] attribute
Digit separators
The following are the main additions and improvements to the C++ standard language in C++14.
There are also miscellaneous smaller improvements and bug fixes besides those listed here,
including various “transparent” improvements of the “now guarantees the program does what you
would expect in a corner case you didn’t notice yet” variety.
Binary literals
C++ now supports binary literals:
1. // the answer to life, the universe, etc. in...
2. auto a1 = 42; // ... decimal
3. auto a2 = 0x2A; // ... hexadecimal
4. auto a3 = 0b101010; // ... binary
This works well in combination with the new ' digit separators, for example to separate nybbles or
bytes:
1. auto a = 0b100'0001; // ASCII 'A'
See also:
[N3472] James Dennett: Binary Literals in the C++ Core Language.
Generalized return type deduction
C++11 permitted automatically deducing the return type of a lambda function whose body consisted
of only a single return statement:
1. // C++11
2. [=]() -> some_type { return foo() * 42; } // ok
3. [=] { return foo() * 42; } // ok, deduces "-> some_type"
This has been expanded in two ways. First, it now works even with more complex function bodies
containing more than one return statement, as long as all return statements return the same type:
1. // C++14
2. [=] { // ok, deduces "-> some_type"
3. while( something() ) {
4. if( expr ) {
5. return foo() * 42; // with arbitrary control flow
6. }
7. }
8. return bar.baz(84); // & multiple returns
9. } // (types must be the same)
Second, it now works with all functions, not just lambdas:
1. // C++11, explicitly named return type
2. some_type f() { return foo() * 42; } // ok
3. auto f() -> some_type { return foo() * 42; } // ok
4.
5. // C++14
6. auto f() { return foo() * 42; } // ok, deduces "-> some_type"
7.
8. auto g() { // ok, deduces "-> some_type"
9. while( something() ) {
10. if( expr ) {
11. return foo() * 42; // with arbitrary control flow
12. }
13. }
14. return bar.baz(84); // & multiple returns
15. } // (types must be the same)
Of course, this requires the function body to be visible.
Finally, someone will ask: “Hmm, does this work for recursive functions?” The answer is yes, as
long as a return precedes the recursive call.
See also:
[N3638] Jason Merrill: Return type deduction for normal functions.
decltype(auto)
Given these functions:
1. string lookup1();
2. string& lookup2();
In C++11 we could write the following wrapper functions which remember to preserve the
reference-ness of the return type:
1. string look_up_a_string_1() { return lookup1(); }
2. string& look_up_a_string_2() { return lookup2(); }
In C++14, we can automate that:
1. decltype(auto) look_up_a_string_1() { return lookup1(); }
2. decltype(auto) look_up_a_string_2() { return lookup2(); }
Note: decltype(auto) is primarily useful for deducing the return type of forwarding functions
and similar wrappers, as shown above, where you want the type to exactly “track” some expression
you’re invoking. However, decltype(auto) is not intended to be a widely used feature beyond
that. In particular, although it can be used to declare local variables, doing that is probably just an
antipattern since a local variable’s reference-ness should not depend on the initialization expression.
Also, it is sensitive to how you write the return statement. These two functions have different return
types:
1. decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }
2. decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); }
The first returns string, the second returns string &, which is a reference to the local
variable str.
See also:
[N3638] Jason Merrill: Return type deduction for normal functions.
Generalized lambda captures
In C++11, lambdas could not (easily) capture by move. In C++14, we have generalized lambda
capture that solves not only that problem, but allows you to define arbitrary new local variables in
the lambda object. For example:
1. auto u = make_unique<some_type>( some, parameters ); // a unique_ptr is move-only
2.
3. go.run( [ u=move(u) ] { do_something_with( u ); } ); // move the unique_ptr into the lambda
In the above example, we kept the name of the variable u the same inside the lambda. But we’re not
limited to that… we can rename variables:
1. go.run( [ u2=move(u) ] { do_something_with( u2 ); } ); // capture as "u2"
And we can add arbitrary new state to the lambda object, because each capture creates a new type-
deduced local variable inside the lambda:
1. int x = 4;
2. int z = [&r = x, y = x+1] {
3. r += 2; // set x to 6; "R is for Renamed Ref"
4. return y+2; // return 7 to initialize z
5. }(); // invoke lambda
See also:
[N3648] Daveed Vandevoorde, Ville Voutilainen: Wording Changes for Generalized
Lambda-capture.
Generic lambdas
Lambda function parameters can now be auto to let the compiler deduce the type. This generates a
lambda type with a templated operator() so that the same lambda object can be invoked with any
suitable type and a type-safe function with the right parameter type will be automatically generated.
In C++11, we had to explicitly state the type of a lambda parameter, which was often fine but
sometimes annoying:
1. // C++11: have to state the parameter type
2.
3. for_each( begin(v), end(v), [](decltype(*cbegin(v)) x) { cout << x; } );
4.
5. sort( begin(w), end(w), [](const shared_ptr<some_type>& a,
6. const shared_ptr<some_type>& b) { return *a<*b; } );
7.
8. auto size = [](const unordered_map<wstring, vector<string>>& m) { return m.size(); };
In C++14, we can get type deduction for the same functions we could write in C++11:
1. // C++14: just deduce the type
2.
3. for_each( begin(v), end(v), [](const auto& x) { cout << x; } );
4.
5. sort( begin(w), end(w), [](const auto& a, const auto& b) { return *a<*b; } );
On top of that, we can now express something new we couldn’t express before, namely a lambda
that will work with any suitable type and just do the right thing:
1. // C++14: new expressive power
2.
3. auto size = [](const auto& m) { return m.size(); };
Note that this new version of size is not limited to unordered_map<wstring,
vector<string>>s, but can be invoked with any type that has a .size() member function.
Furthermore, because it also implicitly deduces the return type, the return type will be
whatever m.size() returns, which can be different for different types.
See also:
[N3559] Faisal Vali, Herb Sutter, Dave Abrahams: Proposal for Generic (Polymorphic)
Lambda Expressions.
[N3649] Faisal Vali, Herb Sutter, Dave Abrahams: Generic (Polymorphic) Lambda
Expressions (Revision 3).
Variable templates
In C++11, the addition of using type aliases and constexpr functions largely replaced the need
for “traits” templates. If you want to compute a type then prefer using a templated type
alias alias_t<T> instead of a traits<T>::type, and if you want to compute a value then prefer
using a value_v(); function that is constexpr instead of a traits<T>::value.
So far, so good. But it turns out that sometimes we end up creating constexpr functions only to
return a constant, and since we can templatize the function we can return the constant “cast” to the
correct type. But the function only exists because we can’t express a templated variable directly.
Enter the variable template:
1. // math constant with precision dictated by actual type
2. template<typename T> constexpr T pi = T(3.14159265358979323846);
3.
4. // Example use:
5. template<class T> T area_of_circle_with_radius(T r) { return pi<T> * r * r; }
6.
7. // Same use, in a more C++14-stylish way:
8. auto area_of_circle_with_radius = [](auto r) { return pi<decltype(r)> * r * r; };
See also:
[N3651] Gabriel Dos Reis: Variable Templates (Revision 1).
Extended constexpr
In C++11, to make a function constexpr can mean rewriting it. For example, let’s say we have
this constexpr function:
1. constexpr int my_charcmp( char c1, char c2 ) {
2. return (c1 == c2) ? 0 : (c1 < c2) ? : -1 : 1;
3. }
That’s fine and useful for characters, so why not extend it to strings? That would require iteration
over the characters of the string, which C++11 did not allow in constexpr functions, so the C++11
version that supports strings would have to be recursive instead (and a little more complicated).
C++14 now allows more things inside the body of constexpr functions, notably:
local variable declarations (not static or thread_local, and no uninitialized variables)
mutating objects whose lifetime began with the constant expression evaluation
if, switch, for, while, do-while (not goto)
So in C++14, the above function generalized to strings can stay idiomatic, and use a normal loop
directly:
1. constexpr int my_strcmp( const char* str1, const char* str2 ) {
2. int i = 0;
3. for( ; str1[i] && str2[i] && str1[i] == str2[i]; ++i )
4. {}
5. if( str1[i] == str2[i] ) return 0;
6. if( str1[i] < str2[i] ) return -1;
7. return 1;
8. }
C++14 also removes the C++11 rule that constexpr member functions are implicitly const.
See also:
[N3652] Richard Smith: Relaxing constraints on constexpr functions.
The [ [deprecated] ] attribute
The deprecated attribute allows marking an entity deprecated, which makes it still legal to use
but puts users on notice that use is discouraged and may cause a warning message to be printed
during compilation.
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static
data member, a function, an enumeration, or a template specialization.
See also:
[N3760] Alberto Ganesh Barbati: [ [deprecated] ] attribute.
Digit separators
The single-quote character ' can now be used anywhere within a numeric literal for aesthetic
readability. It does not affect the numeric value.
1. auto million = 1'000'000;
2. auto pi = 3.14159'26535'89793;
See also:
[N3781] Lawrence Crowl, Richard Smith, Jeff Snyder, Daveed Vandevoorde: Single-
Quotation-Mark as a Digit Separator.
Shared locking
User-defined literals for std:: types
make_unique
Type transformation _t aliases
The following are the main additions and improvements to the C++ standard library in C++14.
There are also miscellaneous smaller improvements besides those listed here, such as addressing
tuples by type (e.g., get<string>(t)) and being able to omit the type of operator functors
(e.g., greater<>(x) is okay).
Shared locking
See also:
[N3568] Howard Hinnant: Shared locking in C++, Revision 1. This paper contains more
informational material. Note that some features were not approved for C++14.
[N3659] Howard Hinnant: Shared locking in C++, Revision 2. This paper summarizes what
was approved for C++14.
User-defined literals for std:: types
C++11 added user-defined literals, but didn’t use them in the standard library. Now some very
useful and popular ones work:
1. auto a_string = "hello there"s; // type std::string
2. auto a_minute = 60s; // type std::chrono::duration = 60 seconds
3. auto a_day = 24h; // type std::chrono::duration = 24 hours
Note s means “string” when used on a string literal, and “seconds” when used on an integer literal,
without ambiguity.
See also:
[N3642] Peter Sommerlad: User-defined Literals for Standard Library Types (part 1 –
version 4).
make_unique
This fixes an omission:
1. auto p1 = make_shared<widget>(); // C++11, type is shared_ptr
2. auto p2 = make_unique<widget>(); // new in C++14, type is unique_ptr
Unlike make_shared, using make_unique doesn’t add any optimization. What it does do is
enable us to tell people “don’t write naked new any more to allocate an object on the heap” (except
only perhaps in the internals of low-level data structures).
See also:
[N3656] Stephan T. Lavavej: make_unique (Revision 1).
Type transformation _t aliases
As part of the movement of C++ away from “traits” types, C++14 added type aliases to avoid
having to spell out typename and ::type, and actually make the traits more technically usable
because they now work in deduced contexts.
1. // C++11
2. ... typename remove_reference<T>::type ...
3. ... typename make_unsigned<T>::type ...
4.
5. // new in C++14
6. ... remove_reference_t<T> ...
7. ... make_unsigned_t<T> ...
See also:
[N3655] Walter E. Brown: TransformationTraits Redux, v2. Note part 4 was not adopted.
Compiler Dependencies
Save to:
InstapaperPocketReadability
Contents of this section:
How can I create two classes that both know about each
other?
Use a forward declaration.
Sometimes you must create two classes that use each other. This is called a circular dependency. For
example:
1. class Fred {
2. public:
3. Barney* foo(); // Error: Unknown symbol 'Barney'
4. };
5.
6. class Barney {
7. public:
8. Fred* bar();
9. };
The Fred class has a member function that returns a Barney*, and the Barney class has a member
function that returns a Fred*. You may inform the compiler about the existence of a class or
structure by using a “forward declaration”:
1. class Barney;
This line must appear before the declaration of class Fred. It simply informs the compiler that the
name Barney is a class, and further it is a promise to the compiler that you will eventually supply a
complete definition of that class.
What special considerations are needed when forward
declarations are used with member objects?
The order of class declarations is critical.
The compiler will give you a compile-time error if the first class contains an object (as opposed to a
pointer to an object) of the second class. For example,
1. class Fred; // Okay: forward declaration
2.
3. class Barney {
4. Fred x; // Error: The declaration of Fred is incomplete
5. };
6.
7. class Fred {
8. Barney* y;
9. };
One way to solve this problem is to reverse order of the classes so the “used” class is defined before
the class that uses it:
1. class Barney; // Okay: forward declaration
2.
3. class Fred {
4. Barney* y; // Okay: the first can point to an object of the second
5. };
6.
7. class Barney {
8. Fred x; // Okay: the second can have an object of the first
9. };
Note that it is never legal for each class to fully contain an object of the other class since that would
imply infinitely large objects. In other words, if an instance of Fred contains a Barney (as opposed
to a Barney*), and a Barney contains a Fred (as opposed to a Fred*), the compiler will give you
an error.
What special considerations are needed when forward
declarations are used with inline functions?
The order of class declarations is critical.
The compiler will give you a compile-time error if the first class contains an inline function that
invokes a member function of the second class. For example,
1. class Fred; // Okay: forward declaration
2.
3. class Barney {
4. public:
5. void method()
6. {
7. x->yabbaDabbaDo(); // Error: Fred used before it was defined
8. }
9. private:
10. Fred* x; // Okay: the first can point to an object of the second
11. };
12.
13. class Fred {
14. public:
15. void yabbaDabbaDo();
16. private:
17. Barney* y;
18. };
There are a number of ways to work around this problem. One workaround would be to
define Barney::method() with the keyword inline below the definition of class Fred (though
still within the header file). Another would be to define Barney::method() without the
keyword inline in file Barney.cpp. A third would be to use nested classes. A fourth would be to
reverse the order of the classes so the “used” class is defined before the class that uses it:
1. class Barney; // Okay: forward declaration
2.
3. class Fred {
4. public:
5. void yabbaDabbaDo();
6. private:
7. Barney* y; // Okay: the first can point to an object of the second
8. };
9.
10. class Barney {
11. public:
12. void method()
13. {
14. x->yabbaDabbaDo(); // Okay: Fred is fully defined at this point
15. }
16. private:
17. Fred* x;
18. };
Just remember this: Whenever you use forward declaration, you can use only that symbol; you may
not do anything that requires knowledge of the forward-declared class. Specifically you may not
access any members of the second class.
Why can’t I put a forward-declared class in
a std::vector<>?
Because the std::vector<> template needs to know the sizeof() its contained elements, plus
the std::vector<> probably accesses members of the contained elements (such as the copy
constructor, the destructor, etc.). For example,
1. class Fred; // Okay: forward declaration
2.
3. class Barney {
4. std::vector<Fred> x; // Error: the declaration of Fred is incomplete
5. };
6.
7. class Fred {
8. Barney* y;
9. };
One solution to this problem is to change Barney so it uses
a std::vector<> of Fred pointers (raw pointers or smart pointers such as unique_ptr or
shared_ptr) rather than a std::vector<> of Fred objects:
1. class Fred; // Okay: forward declaration
2.
3. class Barney {
4. std::vector<std::unique_ptr<Fred>> x; // Okay: Barney can use Fred pointers
5. };
6.
7. class Fred {
8. Barney* y;
9. };
Another solution to this problem is to reverse the order of the classes so Fred is defined
before Barney:
1. class Barney; // Okay: forward declaration
2.
3. class Fred {
4. Barney* y; // Okay: the first can point to an object of the second
5. };
6.
7. class Barney {
8. std::vector<Fred> x; // Okay: Fred is fully defined at this point
9. };
Just remember this: Whenever you use a class as a template parameter, the declaration of that class
must be complete and not simply forward declared.
Why do some people think x = ++y + y++ is bad?
Because it’s undefined behavior, which means the runtime system is allowed to do weird or even
bizarre things.
The C++ language says you cannot modify a variable more than once between sequence points.
Quoth the standard (section 5, paragraph 4):
Between the previous and next sequence point a scalar object shall have its stored value modified at
most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to
determine the value to be stored.
How can I generate HTML documentation for my classes? Does C++ have anything similar
to javadoc?
Is there a TeX or LaTeX macro that fixes the spacing on “C++”?
Are there any pretty-printers that reformat C++ source code?
Is there a C++-mode for GNU emacs? If so, where can I get it?
Where can I get OS-specific questions answered (e.g., BC++, Windows, etc)?
Why does my DOS C++ program says “Sorry: floating point code not linked”?
Why does my BC++ Windows app crash when I’m not running the BC45 IDE?
How can I generate HTML documentation for my classes?
Does C++ have anything similar to javadoc?
Yes. Here are a few (listed alphabetically by tool name):
ccdoc supports javadoc-like syntax with various extensions. It’s freely copiable and
customizable.
doc++ generates HTML or TeX. Supports javadoc-like syntax with various extensions.
Open Source.
doxygen generates HTML, LaTeX or RTF. Supports javadoc-like syntax with various
extensions. Open Source.
PERCEPS generates HTML, TeX, RTF, man page, plain text, and anything else you’d like
(it lets you set up arbitrary output formats). It’s freely copiable.
Other documentation tools are listed at www.robertnz.net/cpp_site.html.
Is there a TeX or LaTeX macro that fixes the spacing on
“C++”?
Yes.
Here are two LaTeX macros for the word “C++”. They prevent line breaks between the “C” and “+
+”, and the first packs the two “+”s close to each other but the second does not. Try them both and
see which one you like best.
1. \newcommand{\CC}{C\nolinebreak\hspace{-.05em}\raisebox{.4ex}{\tiny\bf +}\nolinebreak\
hspace{-.10em}\raisebox{.4ex}{\tiny\bf +}}
2.
3. \def\CC{{C\nolinebreak[4]\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}
Here are two more LaTeX macros for the word “C++”. They allow line breaks between the “C” and
“++”, which may not be desirable, but they’re included here just in case.
1. \def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize +}}
2.
3. \def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}