Bjarne Stroustrup - The Essence of C++ With Examples in C++84, C++98, C++11, and C++14
Bjarne Stroustrup - The Essence of C++ With Examples in C++84, C++98, C++11, and C++14
Bjarne Stroustrup
Texas A&M University
www.stroustrup.com
Overview
• Aims and constraints
• C++ in four slides
• Resource management
• OOP: Classes and Hierarchies
– (very briefly)
• GP: Templates
– Requirements checking
• Challenges
• Experts
– “C++ is expert friendly”
• Novices
– C++ Is not just expert friendly
It’s C!
Classes
Embedded systems
Too big! programming language
Low level!
Generic programming
An object-oriented
programming language A random collection
Stroustrup - Essence - Going Native'13
of features 6
C++
A light-weight abstraction
programming language
Key strengths:
• software infrastructure
• resource-constrained applications
Stroustrup - Essence - Going Native'13 7
Programming Languages
Domain-specific
abstraction
General-purpose abstraction
Fortran
C++ C++11
Direct mapping to
hardware
C#
Assembler BCPL C
value
• Objects can be composed by simple concatenation:
– Arrays
– Classes/structs
value handle
value
value handle
value
template<typename C>
void sort (Cont& c) { /* … */ } // a generic function
sort(constants); // a use
Stroustrup - Essence - Going Native'13 14
Not C++ (fundamental)
• No crucial dependence on a garbage collector
– GC is a last and imperfect resort
• No guaranteed type safety
– Not for all constructs
– C compatibility, history, pointers/arrays, unions, casts, …
• No virtual machine
– For many reasons, we often want to run on the real machine
– You can run on a virtual machine (or in a sandbox) if you want to
void fct()
{
Vector v {1, 1.618, 3.14, 2.99e8}; // vector of doubles
// …
Stroustrup - Essence - Going Native'13 18
}
Resource management
• A handle usually is scoped
– Handles lifetime (initialization, cleanup), and more
Vector::Vector(initializer_list<double> lst)
:elem {new double[lst.size()]}, sz{lst.size()}; // acquire memory
{
uninitialized_copy(lst.begin(),lst.end(),elem); // initialize elements
}
Vector::~Vector()
{
delete[] elem; // destroy elements; release memory
};
void f()
{
std::lock_guard lck {mtx}; // grab (acquire) the mutex
sh+=1; // manipulate shared data
} // implicitly release the mutex
• To represent ownership
– Don’t! Instead, use handles
• To reference resources
– from within a handle
• To represent positions
– Be careful
• To pass large amounts of data (into a function)
– E.g. pass by const reference
• To return large amount of data (out of a function)
– Don’t! Instead use move operations
Stroustrup - Essence - Going Native'13 25
How to get a lot of data cheaply out of a function?
• Ideas
– Return a pointer to a new’d object
• Who does the delete?
- Return a reference to a new’d object
- Who does the delete?
- Delete what?
- Pass a target object
- We are regressing towards assembly code
- Return an object
- Copies are expensive
- Tricks to avoid copying are brittle
- Tricks to avoid copying are not general
- Return a handle
- Simple and cheap
Stroustrup - Essence - Going Native'13 26
Move semantics
• Return a Matrix
Matrix operator+(const Matrix& a, const Matrix& b)
{
Matrix r;
// copy a[i]+b[i] into r[i] for each i
return r;
}
Matrix res = a+b;
• Define move a constructor for Matrix
– don’t copy; “steal the representation” r:
res:
……..
Stroustrup - Essence - Going Native'13 27
Move semantics
• Direct support in C++11: Move constructor
class Matrix {
Representation rep;
// …
Matrix(Matrix&& a) // move constructor
{
rep = a.rep; // *this gets a’s elements
a.rep = {}; // a becomes the empty Matrix
}
};
r:
Matrix res = a+b;
res:
……..
Stroustrup - Essence - Going Native'13 28
No garbage collection needed
• For general, simple, implicit, and efficient resource management
• Apply these techniques in order:
1. Store data in containers
• The semantics of the fundamental abstraction is reflected in the interface
• Including lifetime
2. Manage all resources with resource handles
• RAII
• Not just memory: all resources
3. Use “smart pointers”
• They are still pointers
4. Plug in a garbage collector
• For “litter collection”
• C++11 specifies an interface
• Can still leak non-memory resources
Stroustrup - Essence - Going Native'13 29
Range-for, auto, and move
• As ever, what matters is how features work in combination
template<typename C, typename V>
vector<Value_type<C>*> find_all(C& c, V v) // find all occurrences of v in c
{
vector<Value_type<C>*> res;
for (auto& x : c)
if (x==v)
res.push_back(&x);
return res;
}
• Multiple inheritance
– Separately consider interface and implementation
– Abstract classes provide the most stable interfaces
• Minimal run-time type identification
– dynamic_cast<D*>(pb)
– typeid(p) Stroustrup - Essence - Going Native'13 33
Inheritance
• Use it
– When the domain concepts are hierarchical
– When there is a need for run-time selection among hierarchically ordered
alternatives
• Warning:
– Inheritance has been seriously and systematically overused and misused
• “When your only tool is a hammer everything looks like a nail”
// …
} Stroustrup - Essence - Going Native'13 38
Algorithms
• Simple, efficient, and general implementation
– For any forward iterator
– For any (matching) value type
// …
}
struct Less_than {
String s;
Less_than(const string& ss) :s{ss} {} // store the value to compare against
bool operator()(const string& v) const { return v<s; } // the comparison
};
Lambda notation
– We can let the compiler write the function object for us
auto p = std::find_if(vs.begin(),vs.end(),
[](const string& v) { return v<"Griffin"; } );
Stroustrup - Essence - Going Native'13 42
Container algorithms
• The C++ standard-library algorithms are expressed in terms of half-open
sequences [first:last)
– For generality and efficiency
– If you find that verbose, define container algorithms
namespace Extended_STL {
// …
template<typename C, typename Predicate>
Iterator<C> find_if(C& c, Predicate pred)
{
return std::find_if(c.begin(),c.end(),pred);
}
// …
}
• Generic code
void sort(Container& c); // C++14: accept any c that is a Container
vector<string> vs { "Hello", "new", "World" };
sort(vs); // fine: vs is a Container
sort(&vs); // error: &vs is not a Container
• Template declaration
template <typename S, typename T>
requires Sequence<S>()
&& Equality_comparable<Value_type<S>, T>()
Iterator_of<S> find(S& seq, const T& value);
• Template use
void use(vector<string>& vs)
{
auto p = find(vs,"Jabberwocky");
// …
} Stroustrup - Essence - Going Native'13 49
C++14 Concepts: Error handling
• Error handling is simple (and fast)
template<Sortable Cont>
void sort(Cont& container);
template<Associative_container C>
Iterator_type<C> find(C& assoc, const Key_type<C>& key);
vector<int> v { /* ... */ };
multiset<int> s { /* … */ };
auto vi = find(v, 42); // calls 1st overload:
// a vector is a Sequence
auto si = find(s, 12-12-12); // calls 2nd overload:
// a multiset is an Associative_container
template<Bidirectional_iterator Iter>
void advance(Iter& i, Difference_type<Iter> n)
{ if (n > 0) while (n--) ++p; if (n < 0) while (n++) --ip}
template<Random_access_iterator Iter>
void advance(Iter& p, Difference_type<Iter> n) { p += n; }
• We don’t say
Input_iterator < Bidirectional_iterator < Random_access_iterator
we compute it
Stroustrup - Essence - Going Native'13 53
C++14 Concepts: Definition
• How do you write constraints?
– Any bool expression
• Including type traits and constexpr function
– a requires(expr) expression
• requires() is a compile time intrinsic function
• true if expr is a valid expression
• To recognize a concept syntactically, we can declare it concept
– Rather than just constexpr
• The
concept-name { identifier-list }
notation introduces constrained names