Bjarne Stroustrup presentation at Universidad Carlos III de Madrid, march 18 2011 on :
- The design of C++0x
- C++: Machine model and resource management
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Trends and future of C++: Evolving a systems language for performance - by Bjarne Stroustrup
1. Trends and future of C++
Bjarne Stroustrup
Texas A&M University
http://www.research.att.com/~bs
• Machine, Abstraction, and Resources
• The Design of C++0x
3. Overview
• “The gap:” systems programming
• C++
• Mapping to the machine
• Low-overhead abstraction
• Resource management
Stroustrup - Madrid'11 4
4. Infrastructure
• Bridging the abstraction gap
Application Application Application Application
“The gap”
Foundation/Infrastructure
Systems programming
hardware hardware hardware
Stroustrup - Madrid'11 5
5. Infrastructure – Examples
• .Net
• JVM
• Model driven development environments
• Browser
• Scripting engine
• Game engine
• Some aspects of enterprise architectures
• Some aspects of operating systems
• Embedded systems architectures
• …
Stroustrup - Madrid'11 6
6. Infrastructure
• Is a platform
– Differentiates corporations, communities, organizations
• Expensive to
– Build , port , and maintain
• Designed, built, and maintained by expert developers
– Differ from application developers in attitude and skills
• Critical for applications
– Ease of development
– Stability over time (sometimes decades)
– Maintenance
– Portability across hardware
– Performance
Stroustrup - Madrid'11 7
7. Systems Programming
• Not just bit-fiddling
– Not even mostly bit-fiddling
• Classical systems programming
– Demanding on designers and programmers
• High complexity
– Layering, Modularity
• Hardware differs and matters
– Some code must differ even on different processors of the same architecture
• Concurrency
– Memory architecture, Multi-cores, Physical distribution
• High reliability requirements
– Typically 24/7
• Large programs/libraries/systems
– N*100K lines Stroustrup - Madrid'11 8
8. Programming languages
• A programming language exists to help people express ideas
– Programming language
features exist to serve
design and programming
techniques
– The real measure of value
is the number, novelty,
and quality of applications
Stroustrup - Madrid'11 9
9. Programming Languages
Domain-specific
abstraction
General-purpose abstraction
Fortran
Simula Java
Cobol
C++ C++0x
Direct mapping to
hardware
C#
Assembler BCPL C
10 Stroustrup - Madrid'11
10. ISO Standard C++
• C++98: ISO standard since 1998
– Millions of programmers
– Billions of lines of code deployed
– Massive support
• C++0x: next ISO standard
– Probably 2011
• We have a “Final Committee Draft”
– Many language features already available
• GCC, Microsoft, IBM, Apple, etc.
– Standard libraries widely available
Stroustrup - Madrid'11 11
11. Ideals
• Work at the highest feasible level of abstraction
– More correct, comprehensible, and maintainable code
• Represent
– concepts directly in code
– independent concepts independently in code
• Represent relationships among concepts directly
– For example
• Hierarchical relationships (object-oriented programming)
• Parametric relationships (generic programming)
• Combine concepts
– freely
– but only when needed and it makes sense
Stroustrup - Madrid'11 12
12. C++ maps directly onto hardware
• Mapping to the machine
– Simple and direct
– Built-in types
• fit into registers
• Matches machine instructions
• Abstraction
– User-defined types are created by simple composition
– Zero-overhead principle:
• what you don’t use you don’t pay for
• What you do use, you couldn’t hand code any better
Stroustrup - Madrid'11 13
13. Memory model
Memory is sequences of objects addressed by pointers
Stroustrup - Madrid'11 14
14. Memory model (built-in type)
• char
• short
• int
• long
• (long long)
• float
• double
• long double
• T* (pointer)
• T& (implemented as pointer)
Stroustrup - Madrid'11 15
15. Memory model (“ordinary” class)
class Point {
int x, y;
p12: 1
// …
}; 2
// sizeof(Point)==2*sizeof(int)
p:
Point p12(1,2); Heap
info
Point* p = new Point(1,2);
1
// memory used for “p”:sizeof(Point*)+sizeof(Point)+Heap_info
2
Stroustrup - Madrid'11 16
16. Memory model – class hierarchy
class Base {
int b;
x: b
};
class Derived : public Base {
int d: y: b
};
d
Base x;
Derived y;
Stroustrup - Madrid'11 17
17. Memory model (polymorphic type)
Shape* p = new Circle(x,20);
class Shape {
public: Heap
virtual void draw() = 0; info
virtual Point center() = 0; p->draw();
vptr
// …
};
vtbl:
Circle’s
draw() draw
center
Circle’s
center() Stroustrup - Madrid'11 18
18. Not all memory models are that direct
• Consider a pair of coordinates
– class Coord { double x,y,z; /* operations */ };
– pair<Coord> xy= { {1,2,3}, {4,5,6} };
C++ layout:
xy: 1 2 3 4 5 6 Likely size: 6 words
(2*3 words)
“pure object-oriented” layout:
reference: references: 4 5 6
Likely minimal size: 15 words
(1+(2+2)+2*(2+3) words) 1 2 3
Stroustrup - Madrid'11 19
19. But does it matter?
• Memories are infinitely large (almost )
• Processors are infinitely fast (almost )
• We can use infinitely many processors (almost )
insert:
5
Ordered sequence:
1 2 9 15 19 22
• For which size of sequence is a list faster than a vector?
Stroustrup - Madrid'11 20
20. But does in matter? (it does)
• “Let them eat cache!”
– Compactness of vector vs. list
– Streaming vs. Random access
– Details are very architecture dependent
Stroustrup - Madrid'11 21
22. A class – defined
class vector { // simple vector of double
public: // interface:
// a constructor establishes the class invariant (acquiring resources as needed):
vector(); // constructor: empty vector
vector(initializer_list<double>); // constructor: initialize from a list
~vector(); // destructor for cleanup
double& operator[](int i); // range checked access
const double& operator[](int i) const; // access to immutable vector
int size() const;
// copy and move operations
private: // representation: Think of vector as a resource handle
int sz;
double* p;
}; Stroustrup - Madrid'11 23
23. A generic class – used
• “Our” vector is just an ordinary type used like any other type
vector v1; // global variables
vector s2 = { 1, 2, 3, 4 };
void f(const vector& v) // arguments and local variables
{
for (int i = 0; i<v.size(); ++i) cout << v[i] << ‘n’;
vector s3 = { 1, 2, 3, 5, 8, 13 };
// …
} No explicit resource management
struct S {
vector s1; // class members
vector s2;
Stroustrup - Madrid'11 24
};
24. A class - implemented
class vector { // simple vector of double
public:
vector() :sz(0), elem(0) { }
vector(initializer_list<double> il) :sz(il.size()), elem(new double[sz])
{ uninitialized_copy(il.begin(), il.end(), elem); }
~vector() { delete[] elem; }
double& operator[](int i)
{ if (i<0||sz<=i) throw out_of_range(); return elem[i]; }
const double& operator[](int i) const; // access to immutable vector
int size() const { return sz; }
// copy and move operations
private:
No run-time support system “magic”
int sz;
double* elem;
}; Stroustrup - Madrid'11 25
25. A class – made generic
template<class T> class vector { // simple vector of T
public:
vector() :sz(0), elem(0) { }
vector(initializer_list<T> il) :sz(il.size()), elem(new T[sz])
{ uninitialized_copy(il.begin(), il.end(), elem); }
~vector() { delete[] elem; }
T& operator[](int i)
{ if (i<0||sz<=i) throw out_of_range(); return elem[i]; }
const T& operator[](int i) const; // access to immutable vector
int size() const { return sz; }
// copy and move operations
private: No overheads compared to the non-generic version
int sz;
T* elem;
}; Stroustrup - Madrid'11 26
26. A generic class – used
• “Our” vector is used just like any other type, taking its element
type as an argument
– No fancy runtime system
– No overheads (time or space) compare to hand coding
vector<int> vi;
vector<double> vd = { 1.0, 2, 3.14 }; // exactly like the non-parameterized version
vector<string> vs = {"Hello", "New", "World" };
vector<vector<Coord>> vvc = {
{ {1,2,3}, {4,5,6} },
{},
{ {2,3,4}, {3,4,5}, {4,5,6}, {5,6,7} }
C++0x
};
Stroustrup - Madrid'11 27
27. In real-world code
• We use the standard-library vector
– Fundamentally similar to “our” vector
• same mapping to hardware
• Same abstraction mechanisms
– More refined that “our” vector
– As efficient (same map to hardware)
• or better
• Or we use an industry, corporation, project “standard” container
– Designed to cater for special needs
• Build our own
– Using the same facilities and techniques used for the standard library
• There are tens of thousands of libraries “out there”
– But no really good way of finding them
Stroustrup - Madrid'11 28
28. Maintaining abstraction close to the hardware
• Compile-time resolution
– Templates
– Overloading
• Inline functions
– Saves time and space for tiny functions
– Requires use of values (minimize the use of pointers/indirections)
• Constant expression evaluation
Stroustrup - Madrid'11 29
29. Abstraction is affordable
• Read and sort floating-point numbers
– C: read using stdio; qsort(buf,n,sizeof(double),compare)
– C++: read using iostream; sort(v.begin(),v.end()); slow
#elements C++ C C/C++ ratio
500,000 2.5 5.1 2.04
5,000,000 27.4 126.6 4.62
• How? fast
– clean algorithm
– inlining
(Details: May’99 issue of C/C++ Journal; http://www.research.att.com/~bs/papers.html)
Stroustrup - Madrid'11 30
30. Engine example
• MAN – B&W marine diesel engine
– Up to 132,340Hp
– Has been deployed in very large ships for a couple of years
Stroustrup - Madrid'11 31
32. What is a “resource”?
• A resource is something
Handle
– You acquire (local)
– You use
– You release/free
– Any or all of those steps can be implicit
• Examples
– Free store (heap) memory Resource
(shared over time)
– Sockets
– Locks
– Files
– Threads
Stroustrup - Madrid'11 33
33. Managing Resources
// unsafe, naïve use (common in all languages):
void f(const char* p)
{
FILE* f = fopen(p,"r"); // acquire
// use f
fclose(f); // release
}
Stroustrup - Madrid'11 34
34. Managing Resources
// naïve fix:
void f(const char* p)
{
FILE* f = 0;
try {
f = fopen(p, "r");
// use f
}
catch (…) { // handle every exception
if (f) fclose(f);
throw;
}
if (f) fclose(f);
}
Stroustrup - Madrid'11 35
35. Managing Resources
// use an object to represent a resource (RAII ==“resource acquisition is initialization”)
class File_handle { // belongs in some support library
FILE* p;
public:
File_handle(const string& s, const char* r) // constructor: acquire
{
p = fopen(s.c_str(),r);
if (p==0) throw File_error(s,r);
}
~File_handle() { fclose(p); } // destructor: release
// copy and move operations
// access functions
};
void f(string s)
{
File_handle f(s, "r"); // simpler than “naïve use”
// use f Stroustrup - Madrid'11 36
}
36. Simplified conventional locking
• A lock represents local ownership of a resource (the mutex)
std::mutex m;
int sh; // shared data
void f()
{
// ...
std::unique_lock<mutex> lck(m); // grab (acquire) the mutex
// manipulate shared data:
sh+=1;
} // implicitly release the mutex
C++0x
Stroustrup - Madrid'11 37
37. Summary
• Focus on mapping from “high-level” applications to hardware
– One critical focus among many
– The complexity of this mapping is easily underestimated
• Work at the highest feasible level of abstraction
– For correctness, maintainability, portability, and performance
• A programming language can help
– A suitable programming language
– In the hands of competent programmers
– Good language use is essential (IMO)
• Rely on libraries
– Define and rely on explicit abstractions
– Represent resources directly
• Stay type safe
Stroustrup - Madrid'11 38
38. C++ for safety-critical uses
General strategy: Use a subset of superset
C++ JSF++
MISRA C (a subset of C) C
• JSF++ (a subset of a superset of C++)
– Stricter than any C subset (and far more flexible)
– Type safe Stroustrup - Madrid'11 39
39. More C++ information
• My home pages
– Papers, FAQs, libraries, applications, compilers, …
• Search for “Bjarne” or “Stroustrup”
• C++0x:
– The ISO C++ standard committee’s site:
• All documents from 1994 onwards
– Search for “WG21”
• Design and evolution of of C++
– My HOPL-II and HOPL-III papers
– The Design and Evolution of C++ (Addison Wesley 1994)
– The Computer History Museum
• Software preservation project’s C++ pages
– Early compilers and documentation, etc.
» http://www.softwarepreservation.org/projects/c_plus_plus/
» Search for “C++ Historical Sources Archive”
Stroustrup - Madrid'11 40
40. Thanks!
• C and Simula
– Brian Kernighan
– Doug McIlroy
– Kristen Nygaard
– Dennis Ritchie
– …
• ISO C++ standards committee
– Steve Clamage
– Francis Glassborow
– Andrew Koenig
– Tom Plum
– Herb Sutter
– …
• C++ compiler, tools, and library builders
– Beman Dawes
– David Vandevoorde
– …
• Application builders
Stroustrup - Madrid'11 41
41. The Design of C++0x
Bjarne Stroustrup
Texas A&M University
http://www.research.att.com/~bs
42. Overview
• Aims, Ideals, and history
• C++
• Design rules for C++0x
– With examples
• Case study
– Initialization
Stroustrup - Madrid'11 44
43. Programming languages
• A programming language exists to help people express ideas
• Programming language features
exist to serve design and
programming techniques
• The primary value of a
programming language is in the
applications written in it
• The quest for better languages has been long and must continue
Stroustrup - Madrid'11 45
44. Programming Languages
Domain-specific
abstraction
General-purpose abstraction
Fortran
Simula Java
Cobol
C++ C++0x
Direct mapping to
hardware
C#
Assembler BCPL C
Stroustrup - Madrid'11 46
45. Ideals
• Work at the highest feasible level of abstraction
– More general, correct, comprehensible, and maintainable code
• Represent
– concepts directly in code
– independent concepts independently in code
• Represent relationships among concepts directly
– For example
• Hierarchical relationships (object-oriented programming)
• Parametric relationships (generic programming)
• Combine concepts
– freely
– but only when needed and it makes sense
Stroustrup - Madrid'11 47
46. C with Classes –1980
• General abstraction mechanisms to cope with complexity
– From Simula
• General close-to-hardware machine model for efficiency
– From C
• Became C++ in 1984
– Commercial release 1985
• Non-commercial source license: $75
– ISO standard 1998
– C++0x: Final Draft Standard 2010
• 2nd ISO standard 200x (‘x’ is hex )
Stroustrup - Madrid'11 48
47. C++ ISO Standardization
• Slow, bureaucratic,
democratic, formal process
– “the worst way, except for all the rest”
• (apologies to W. Churchill)
• About 22 nations
(5 to 12 at a meeting)
• Membership have varied
– 100 to 200+
• 200+ members currently
– 40 to 100 at a meeting
• ~60 currently
• Most members work in industry
• Most members are volunteers
– Even many of the company representatives
• Most major platform, compiler, and library vendors are represented
– E.g., IBM, Intel, Microsoft, Sun
• End users are underrepresented
Stroustrup - Madrid'11 52
48. Design?
• Can a committee design?
– No (at least not much)
– Few people consider or care
for the whole language
• Is C++0x designed
– Yes
• Well, mostly: You can see
traces of different
personalities in C++0x
• Committees
– Discuss
– Bring up problems
– “Polish”
– Are brakes on innovation
Stroustrup - Madrid'11 53
49. Overall goals for C++0x
• Make C++ a better language
for systems programming and
library building
– Rather than providing specialized
facilities for a particular sub-
community (e.g. numeric
computation or Windows-style
application development)
– Build directly on C++’s contributions
to systems programming
• Make C++ easier to teach and learn
– Through increased uniformity, stronger guarantees, and
facilities supportive of novices (there will always be more
novices than experts)
Stroustrup - Madrid'11 54
50. C++0x
• ‘x’ may be hex, but C++0x is not science fiction
– Every feature is implemented somewhere
• E.g. GCC 4.6: Rvalues, Variadic templates, Initializer lists, Static
assertions, auto, New function declarator syntax, Lambdas, Right
angle brackets, Extern templates, Strongly-typed enums, constexpr,
Delegating constructors (patch), Raw string literals, Defaulted and
deleted functions, Inline namespaces, noexcept, Local and unnamed
types as template arguments, range-for
– Standard library components are shipping widely
• E.g. GCC, Microsoft, Boost
– The last design points have been settled
• We are processing requests from National Standards Bodies
Stroustrup - Madrid'11 55
51. Rules of thumb / Ideals
• Integrating features to work in combination is the key
– And the most work
– The whole is much more than the simple sum of its part
• Maintain stability and compatibility
• Prefer libraries to language extensions
• Prefer generality to specialization
• Support both experts and novices
• Increase type safety
• Improve performance and ability to work directly with hardware
• Make only changes that change the way people think
• Fit into the real world
Stroustrup - Madrid'11 56
52. Maintain stability and compatibility
• “Don’t break my code!”
– There are billions of lines of code “out there”
• 1 billion == 1000 million
– There are millions of C++ programmers “out there”
• “Absolutely no incompatibilities” leads to ugliness
– We introduce new keywords as needed: auto (recycled), decltype,
constexpr, thread_local, nullptr
– Example of incompatibility:
static_assert(4<=sizeof(int),"error: small ints");
Stroustrup - Madrid'11 57
53. Support both experts and novices
• Example: minor syntax cleanup
vector<list<int>> vl; // note the “missing space”
• Example: get type from initializer
auto v = 7.2; // v is a double (because 7.2. is a double)
• Example: simplified iteration
for (auto x : v) cout << x <<'n';
• Note: Experts don’t easily appreciate the needs of novices
– Example of what we couldn’t get just now
string s = "12.3";
double x = lexical_cast<double>(s); // extract value from string
Stroustrup - Madrid'11 58
54. Prefer libraries to language extensions
• Libraries deliver more functionality
• Libraries are immediately useful
• Problem: Enthusiasts prefer language features
– see library as 2nd best
• Example: New library components
– std::thread, std::future, …
• Threads ABI; not thread built-in type
– std::unordered_map, std::regex, …
• Not built-in associative array
Stroustrup - Madrid'11 59
55. Prefer generality to specialization
• Example: Prefer improvements to abstraction mechanisms
over separate new features
– Inherited constructor
template<class T> class Vector : std::vector<T> {
using vector::vector<T>; // inherit all constructors
// …
};
– Move semantics supported by rvalue references
template<class T> class vector {
// …
void push_back(T&& x); // move x into vector
// avoid copy if possible
};
• Problem: people love small isolated features
Stroustrup - Madrid'11 60
56. Not a reference
Move semantics
• Often we don’t want two copies, we just want to move a value
vector<int> make_test_sequence(int n)
{
vector<int> res;
for (int i=0; i<n; ++i) res.push_back(rand_int());
return res; // move, not copy
}
vector<int> seq = make_test_sequence(1000000); // no copies
• New idiom for arithmetic operations:
– Matrix operator+(const Matrix&, const Matrix&);
– a = b+c+d+e; // no copies
Stroustrup - Madrid'11 61
57. Increase type safety
• Approximate the unachievable ideal
– Example: Strongly-typed enumerations
enum class Color { red, blue, green };
int x = Color::red; // error: no Color->int conversion
Color y = 7; // error: no int->Color conversion
Color z = red; // error: red not in scope
Color c = Color::red; // fine
– Example: Support for general resource management
• std::unique_ptr (for ownership)
• std::shared_ptr (for sharing)
• Garbage collection ABI
Stroustrup - Madrid'11 62
58. Improve performance and the ability to work
directly with hardware
• Embedded systems programming is very important
– Example: address array/pointer problems
• array<int,7> s; // fixed-sized array
– Example: Generalized constant expressions (think ROM)
constexpr int abs(int i) { return (0<=i) ? i : -i; } // can be constant expression
struct Point { // “literal type” can be used in constant expression
int x, y;
constexpr Point(int xx, int yy) : x{xx}, y{yy} { }
};
constexpr Point p1{1,2}; // must be evaluated at compile time: ok
constexpr Point p2{p1.y,abs(x)}; // ok?: is x is a constant expression?
Stroustrup - Madrid'11 63
59. Make only changes that change
the way people think
• Think/remember:
– Object-oriented programming
– Generic programming
– Concurrency
– …
• But, most people prefer to fiddle with details
– So there are dozens of small improvements
• All useful somewhere
• long long, static_assert, raw literals, thread_local, unicode types, …
– Example: A null pointer keyword
void f(int);
void f(char*);
f(0); // call f(int);
f(nullptr); // call f(char*);
Stroustrup - Madrid'11 64
60. Fit into the real world
• Example: Existing compilers and tools must evolve
– Simple complete replacement is impossible
– Tool chains are huge and expensive
– There are more tools than you can imagine
– C++ exists on many platforms
• So the tool chain problems occur N times
– (for each of M tools)
• Example: Education
– Teachers, courses, and textbooks
• Often mired in 1970s thinking (“C is the perfect language”)
• Often mired in 1980s thinking (“OOP: Rah! Rah!! Rah!!!”)
– “We” haven’t completely caught up with C++98!
• “legacy code breeds more legacy code”
Stroustrup - Madrid'11 65
61. Areas of language change
• Machine model and concurrency Model
– Threads library (std::thread)
– Atomics ABI
– Thread-local storage (thread_local)
– Asynchronous message buffer (std::future)
• Support for generic programming
– (no concepts )
– uniform initialization
– auto, decltype, lambdas, template aliases, move semantics, variadic
templates, range-for, …
• Etc.
– static_assert
– improved enums
– long long, C99 character types, etc.
– … Stroustrup - Madrid'11 66
62. Standard Library Improvements
• New containers
– Hash Tables (unordered_map, etc.)
– Singly-linked list (forward_list)
– Fixed-sized array (array)
• Container improvements
– Move semantics (e.g. push_back)
– Intializer-list constructors
– Emplace operations
– Scoped allocators
• More algorithms (just a few)
• Concurrency support
– thread, mutex, lock, …
– future, async, …
– Atomic types
• Garbage collection ABI
Stroustrup - Madrid'11 67
63. Standard Library Improvements
• Regular Expressions (regex)
• General-purpose Smart Pointers (unique_ptr, shared_ptr, …)
• Extensible Random Number Facility
• Enhanced Binder and function wrapper (bind and function)
• Mathematical Special Functions
• Tuple Types (tuple)
• Type Traits (lots)
Stroustrup - Madrid'11 68
64. Template What is C++?
meta-programming!
A hybrid language
A multi-paradigm
programming language
Buffer
overflows
It’s C!
Embedded systems
Too big! programming language
Supports
generic programming
Low level!
An object-oriented A random collection
programming language Stroustrup - Madrid'11 of features 69
65. C++0x
• It feels like a new language
– Compared to C++98
• It’s not just “object oriented”
– Many of the key user-defined abstractions are not objects
• Types
• Classifications and manipulation of types (types of types)
– I miss “concepts”
• Algorithms (generalized versions of computation)
• Resources and resource lifetimes
• The pieces fit together much better than they used to
Stroustrup - Madrid'11 70
66. C++
Key strength:
Building
software
infrastructures
and resource-
constrained
applications
A light-weight abstraction
programming language
Stroustrup - Madrid'11 71
67. So, what does “light-weight abstraction” mean?
• The design of programs focused on the design,
implementation, and use of abstractions
– Often abstractions are organized into libraries
• So this style of development has been called “library-oriented”
• C++ emphasis
– Flexible static type system
– Small abstractions
– Performance (in time and space)
– Ability to work close to the hardware
Stroustrup - Madrid'11 72
68. Case studies
• Initialization
– “language maintenance”
• Simplification through generalization
• Concurrency
– “a necessity”
• Design under severe constraints
Stroustrup - Madrid'11 73
69. Case study: Initializers
• The problems
– #1: Irregularity
– #2: Lack of adequate variable-length list mechanism
– #3: Narrowing
• Constraints
– About 35 years of history
• The bigger picture
– Uniform initialization syntax and semantics needed
• The solution
– { } uniform initialization
• Uniform syntax
• Uniform semantics
Stroustrup - Madrid'11 74
70. Problem #1: irregularity
• There are four notations
– int a = 2; // “assignment style”
– int aa[] = { 2, 3 }; // “list style”
– complex z(1,2); // “functional style”
– x = Ptr(y); // “functional style” for conversion/cast/construction
• No notation can be used everywhere
– p = (new int = 2); // error: no = initialization for free store objects
– complex z{1,2}; // error: complex has a constructor
– int aa[](2,3); // error: an array doesn’t have a constructor
– x = Ptr{3}; // syntax error: you can’t cast from a list
Stroustrup - Madrid'11 75
71. Problem #1: irregularity
• Sometimes, the syntax is inconsistent/confusing
int a(1); // variable definition
int b(); // function declaration
int b(foo); // variable definition or function declaration
• We can’t use initializer lists except in a few cases
string a[] = { "foo", " bar" }; // ok: initialize array variable
vector<string> v = { "foo", " bar" }; // error: initialize vector variable
void f(string a[]);
f( { "foo", " bar" } ); // error: initializer array argument
Stroustrup - Madrid'11 76
72. Is irregularity a real problem?
• Yes, a major source of confusion and bugs
• Violates a fundamental C++ design principle:
– Provide uniform support for types (user-defined and built-in)
• Can it be solved by restriction?
– No existing syntax can be used in all cases
int a [] = { 1,2,3 }; // can’t use () here
complex<double> z(1,2); // can’t use { } here
struct S { double x,y; } s = {1,2}; // can’t use ( ) here
int* p = new int(4); // can’t use { } or = here
– No existing syntax has the same semantics in all cases
typedef char* Pchar;
Pchar p(7); // error (good!)
Pchar p = Pchar(7); // “legal” (ouch!)
Stroustrup - Madrid'11 77
73. Problem #2: list workarounds
• Initialize a vector (using push_back)
– Clumsy and indirect
template<class T> class vector {
// …
void push_back(const T&) { /* … */ }
// …
};
vector<double> v;
v.push_back(1); v.push_back(2); v.push_back(3.4);
• Violates a fundamental C++ design principle:
– Support fundamental notions directly (“state intent”)
Stroustrup - Madrid'11 78
74. Problem #2: list workarounds
• Initialize vector (using general iterator constructor)
– Awkward, error-prone, and indirect
– Spurious use of (unsafe) array
template<class T> class vector {
// …
template <class Iter>
vector(Iter first, Iter last) { /* … */ }
// …
};
int a[ ] = { 1, 2, 3.4 }; // bug
vector<double> v(a, a+sizeof(a)/sizeof(int)); // hazard
• Violates a fundamental C++ design principle:
– Provide uniform support for types (user-defined and built-in)
Stroustrup - Madrid'11 79
75. C++0x: initializer lists
• An initializer-list constructor
– defines the meaning of an initializer list for a type
template<class T> class vector {
// …
vector(std::initializer_list<T>); // initializer list constructor
// …
};
vector<double> v = { 1, 2, 3.4 };
vector<string> geek_heros = {
"Dahl", "Kernighan", "McIlroy", "Nygaard ", "Ritchie", "Stepanov"
};
Stroustrup - Madrid'11 80
76. C++0x: initializer lists
• Not just for templates and constructors
– but std::initializer list is simple – does just one thing well
void f(int, std::initializer_list<int>, int);
f(1, {2,3,4}, 5);
f(42, {1,a,3,b,c,d,x+y,0,g(x+a),0,0,3}, 1066);
Stroustrup - Madrid'11 81
77. Uniform initialization syntax
• Every form of initialization can accept the { … } syntax
X x1 = X{1,2};
X x2 = {1,2}; // the = is optional
X x3{1,2};
X* p2 = new X{1,2};
struct D : X {
D(int x, int y) :X{x,y} { /* … */ };
};
struct S {
int a[3];
S(int x, int y, int z) :a{x,y,z} { /* … */ }; // solution to old problem
}; Stroustrup - Madrid'11 82
78. Uniform initialization semantics
• X { a } constructs the same value in every context
– { } initialization gives the same result in all places where it is legal
X x{a};
X* p = new X{a};
z = X{a}; // use as cast
f({a}); // function argument (of type X)
return {a}; // function return value (function returning X)
…
• X { … } is always an initialization
– X var{}; // no operand; default initialization
• Not a function definition like X var();
– X var{a}; // one operand
• Never a function definition like X var(a); (if a is a type name)
Stroustrup - Madrid'11 83
79. Initialization problem #3: narrowing
• C++98 implicitly truncates
int x = 7.3; // Ouch!
char c = 2001; // Ouch!
int a[] = { 1,2,3.4,5,6 }; // Ouch!
void f1(int); f1(7.3); // Ouch!
void f2(char); f2(2001); // Ouch!
void f3(int[]); f3({ 1,2,3.4,5,6 }); // oh! Another problem
• A leftover from before C had casts!
• Principle violated: Type safety
• Solution:
– C++0x { } initialization doesn’t narrow.
• all examples above are caught
Stroustrup - Madrid'11 84
80. Uniform Initialization
• Example
Table phone_numbers = {
{ "Donald Duck", 2015551234 },
{ “Mike Doonesbury", 9794566089 },
{ "Kell Dewclaw", 1123581321 }
};
• What is Table?
– a map? An array of structs? A vector of pairs? My own class with a
constructor? A struct needing aggregate initialization? Something else?
– We don’t care as long as it can be constructed using a C-style string
and an integer.
– Those numbers cannot get truncated
Stroustrup - Madrid'11 85
81. Concurrency support
• Memory model
– To guarantee our usual assumptions
• Support for concurrent systems programming
– Atomic types for implementing concurrency support features
• “Here be dragons”
• Lock-free programming
– Thread, mutex, lock, …
• RAII for locking
• Type safe
• A single higher-level model
– async() and futures
Spring'11 Stroustrup 86
82. What we want
• Ease of programming
– Writing correct concurrent code is hard
– Modern hardware is concurrent in more way than you imagine
• Uncompromising performance
– But for what?
• Portability
– Preferably portable performance
• System level interoperability
– C++ shares threads with other languages and with the OSs
Stroustrup - Madrid'11 87
83. We can’t get everything
• No one concurrency model is best for everything
• We can’t get all that much
– C++0x is not a research project
– WG21 has very few resources (time, people)
– “Don’t break my code!”
• “C++ is a systems programming language”
– (among other things) implies serious constraints
Stroustrup - Madrid'11 88
84. Memory model
• A memory model is an agreement between the machine
architects and the compiler writers to ensure that most
programmers do not have to think about the details of modern
computer hardware.
// thread 1: // thread 2:
char c; char b;
c = 1; b = 1; c: b:
int x = c; int y = b;
x==1 and y==1 as anyone would expect
(but don’t try that for two bitfields of the same word)
Stroustrup - Madrid'11 89
85. Atomics (“here be dragons!”)
• Components for fine-grained atomic access
– provided via operations on atomic objects (in <cstdatomic>)
– Low-level, messy, and shared with C (making the notation messy)
– what you need for lock-free programming
– what you need to implement std::thread, std::mutex, etc.
– Several synchronization models, CAS, fences, …
enum memory_order { // regular (non-atomic) memory synchronization order
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
};
C atomic_load_explicit(const volatile A* object, memory_order);
void atomic_store_explicit(volatile A *object, C desired, memory_order order);
bool atomic_compare_exchange_weak_explicit(volatile A* object, C * expected, C
desired, memory_order success, memory_order failure);
// … lots more …
Stroustrup - Madrid'11 91
86. Threading
• 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
Stroustrup - Madrid'11 92
87. Concurrency: std::thread
#include<thread>
void f() { std::cout << "Hello "; }
struct F {
void operator()() { std::cout << "parallel world "; }
};
int main()
{
std::thread t1{f}; // f() executes in separate thread
std::thread t2{F()}; // F()() executes in separate thread
} // spot the bugs
Stroustrup - Madrid'11 93
88. Concurrency: std::thread
int main()
{
std::thread t1{f}; // f() executes in separate thread
std::thread t2{F()}; // F()() executes in separate thread
t1.join(); // wait for t1
t2.join(); // wait for t2
}
// and another bug: don’t write to cout without synchronization
Stroustrup - Madrid'11 94
89. Thread – pass arguments
• Use function object or bind()
void f(vector<double>&);
struct F {
vector<double>& v;
F(vector<double>& vv) :v{vv} { }
void operator()();
};
int main()
{
std::thread t1{std::bind(f,some_vec)}; // f(some_vec)
std::thread t2{F(some_vec)}; // F(some_vec)()
t1.join(); t2.join();
} Stroustrup - Madrid'11 95
91. Thread – pass result (primitive)
void f(vector<double>&, double* res); // place result in res
struct F {
vector& v; double* res;
F(vector<double>& vv, double* p) :v{vv}, res{p} { }
void operator()(); // place result in res
};
int main()
{
double res1; double res2;
std::thread t1{f,some_vec,&res1}; // f(some_vec,&res1)
std::thread t2{F,some_vec,&res2}; // F(some_vec,&res2)()
t1.join(); t2.join();
std::cout << res1 << ' ' << res2 << 'n';
Stroustrup - Madrid'11 97
}
92. Mutual exclusion: std::mutex
• A mutex is a primitive object use for controlling access in a
multi-threaded system.
• A mutex is a shared object (a resource)
• Simplest use:
std::mutex m;
int sh; // shared data
// ...
m.lock();
// manipulate shared data:
sh+=1;
m.unlock();
Stroustrup - Madrid'11 99
93. Mutex – try_lock()
• Don’t wait unnecessarily
std::mutex m;
int sh; // shared data
// ...
if (m.try_lock()) { // manipulate shared data:
sh+=1;
m.unlock();
}
else {
// maybe do something else
}
Stroustrup - Madrid'11 100
94. Mutex – try_lock_for()
• Don’t wait for too long:
std::timed_mutex m;
int sh; // shared data
// ...
if (m.try_lock_for(std::chrono::seconds(10))) { // Note: time
// manipulate shared data:
sh+=1;
m.unlock();
}
else {
// we didn't get the mutex; do something else
}
Stroustrup - Madrid'11 101
95. Mutex – try_lock_until()
• We can wait until a fixed time in the future:
std::timed_mutex m;
int sh; // shared data
// ...
if (m.try_lock_until(midnight)) { // manipulate shared data:
sh+=1;
m.unlock();
}
else {
// we didn't get the mutex; do something else
}
Stroustrup - Madrid'11 102
96. Recursive mutex
• In some important use cases it is hard to avoid recursion
std::recursive_mutex m;
int sh; // shared data
// ...
void f(int i)
{
// ...
m.lock();
// manipulate shared data:
sh+=1;
if (--i>0) f(i);
m.unlock();
// ... Stroustrup - Madrid'11 103
}
97. RAII for mutexes: std::lock
• A lock represents local ownership of a non-local resource
(the mutex)
std::mutex m; Lock
(local)
int sh; // shared data
void f()
{ mutex
// ... (shared over time)
std::unique_lock lck(m); // grab (acquire) the mutex
// manipulate shared data:
sh+=1;
} // implicitly release the mutex
Stroustrup - Madrid'11 104
98. Potential deadlock
• Unstructured use of multiple locks is hazardous:
std::mutex m1;
std::mutex m2;
int sh1; // shared data
int sh2;
// ...
void f()
{
// ...
std::unique_lock lck1(m1);
std::unique_lock lck2(m2);
// manipulate shared data:
sh1+=sh2; Stroustrup - Madrid'11 105
}
99. RAII for mutexes: std::lock
• We can safely use several locks
void f()
{
// ...
std::unique_lock lck1(m1,std::defer_lock); // make locks but don't yet
// try to acquire the mutexes
std::unique_lock lck2(m2,std::defer_lock);
std::unique_lock lck3(m3,std::defer_lock);
// …
lock(lck1,lck2,lck3);
// manipulate shared data
} // implicitly release the mutexes
Stroustrup - Madrid'11 106
100. Future and promise
set_value()
get()
future promise
set_exception()
result
• future+promise provides a simple way of passing a
value from one thread to another
– No explicit synchronization
– Exceptions can be transmitted between threads
Stroustrup - Madrid'11 107
101. Future and promise
• Get from a future<X> called f:
X v = f.get();// if necessary wait for the value to get
• Put to a promise<X> called p (attached to f):
try {
X res;
// compute a value for res
p.set_value(res);
} catch (...) {
// oops: couldn't compute res
p.set_exception(std::current_exception());
}
Stroustrup - Madrid'11 108
102. Type-safe simple concurrency
double accum(double* b, double* e, double init);
double comp(vector<double>& v) // spawn many tasks if v is large enough
{
const auto vs = v.size();
if (vs<10000) return accum(&v[0], &v[0]+vs ,0.0);
auto f0 = async(accum, &v[0], &v[vs/4], 0.0); // first quarter
auto f1 = async(accum, &v[vs/4], &v[vs/2], 0.0); // second quarter
auto f2 = async(accum, &v[vs/2], &v[vs*3/4], 0.0); // third quarter
auto f3 = async(accum, &v[vs*3/4], &v[0]+vs, 0.0); // fourth quarter
return f0.get()+f1.get()+f2.get()+f3.get();
C++0x
}
Stroustrup Models Madrid'11 109
103. Thanks!
• C and Simula
– Brian Kernighan
– Doug McIlroy
– Kristen Nygaard
– Dennis Ritchie
– …
• ISO C++ standards committee
– Steve Clamage
– Francis Glassborow
– Andrew Koenig
– Tom Plum
– Herb Sutter
– …
• C++ compiler, tools, and library builders
– Beman Dawes
– David Vandevoorde
– …
• Application builders
Stroustrup - Madrid'11 110
104. More information
• My home pages
– C++0x FAQ
– Papers, FAQs, libraries, applications, compilers, …
• Search for “Bjarne” or “Stroustrup”
• “What is C++0x ?” paper
• My HOPL-II and HOPL-III papers
• The Design and Evolution of C++ (Addison Wesley 1994)
• The ISO C++ standard committee’s site:
– All documents from 1994 onwards
• Search for “WG21”
• The Computer History Museum
– Software preservation project’s C++ pages
• Early compilers and documentation, etc.
– http://www.softwarepreservation.org/projects/c_plus_plus/
– Search for “C++ Historical Sources Archive”
Stroustrup - Madrid'11 111