.pdf

IBM Research – Zurich
Business Integration Technologies
C++ (10. Vorlesung)
C++11, Factories, Multi Methods
Thomas Gschwind
<thg@zurich....>
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Agenda
C++11
Factories (Virtual Constructors)
– Factories
– Clone
– Exemplars
Multi methods
2
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Introduction
History
– Last change to C++ was about 10 years ago (C++03)
– Many features already included in several compilers
– Final specification in 2011
Does not relieve the engineer
Difficult to change language
from choosing good algorithms!
– Compatibility – new keywords could clash with old code
– Goal to make it easier for “newbies” and better for experts
Keep the original design goals
–
–
–
–
Generate programs of high performance
Versatile
Don’t force a specific paradigm
Keep zero overhead principle – A feature that is unused must not cost anything
Language and libraries are both part of the standard
– Java was the “first” language to include the library as part of the standard
3
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Language Changes
The nullptr
The auto type
Constant Expressions
Range for
Lambda functions
Initializer lists
Constructors
4
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
nullptr
New way for saying NULL
Frequently defined as 0 => problems with ints
5
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Range For (foreach) Operator
Copied over from Java
(which copied it over from C# (which …))
Easier to use than C++’s standard for function
Useful in combination with initializer lists
void print(const vector<int> &v) {
for(const auto &i : v) {
cout << i << endl;
}
}
10
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Initializer Lists
Want to initialize a vector with a set of elements? Don’t like to use a series of
push_back calls?
=> Initializer lists are for you
Represents a list of values
New constructor invocation
Standard library containers modified to support this
#include<initializer_list>
class MyVec {
int *a;
public:
MyVec(initializer_list<int> seq) : a(new int[seq.size()]) {
copy(seq.begin(), seq.end(), a);
};
MyVec squares{0,1,4,9,16};
12
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Constructors
Constructors may invoke other constructors
– For instance, for our own String class, we could provide
String() : String(NULL) {}
Constructors may be derived
– For instance, in the subclass to derive all constructors from Base, include
using Base::Base;
Copy constructor may be explicitly removed
(same for the assignment operator)
– Simply declare as
pvector(const pvector&) = delete;
pvector& operator=(const pvector&) = delete;
13
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Calling Constructors
C++11 allows to call peer constructors
Similar to Java
Can make code more readable
class SomeType
int number;
{
public:
SomeType(int new_number) : number(new_number) {}
SomeType() : SomeType(42) {}
};
14
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Standard Library Changes
Hash tables (unordered_map/set)
Threads
unique_ptr, shared_ptr, weak_ptr
Regular Expressions
15
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Threads (Starting and Joining)
So far, C++ developers had to rely on
– BOOST thread library, POSIX threads, Other non-standard solutions
C++ provides a thread class
– Needs to be passed to a functor (function, function object, lambda function)
– The new thread is started immediately
– Threads may be joined with the join() member function
#include<thread>
struct printchar {
char c;
printchar(char ch) : ch(c) {}
void operator()() { for(int i=0; i<9999; ++i) cout << c; }
}
int main(int argc, char *argv[]) {
thread t1(printchar(‘a’)), t2(printchar(‘b’));
t1.join(); t2.join(); }
17
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Threads (Mutexes)
Similar to the Java synchronized(object) { … } mechanism
C++ provides mutexes
However, instead of changing the language,
it is implemented as library (but almost invisible to developers)
#include<thread>
mutex mtx;
int cnt=0;
struct printchar {
char c;
printchar(char ch) : ch(c) {}
void operator()() {
for(int i=0; i<9999; ++i) {
{ lock_guard lock(mtx); ++cnt; }
cout << c;
} } }
18
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Threads (Async Executions, Futures)
Asynchronous execution is provided by the async function
Async is clever enough to know the platform and only executes
the function in a separate thread if beneficial on the platform
template <typename I>
void parsum(I begin, I end) {
int sum=0;
int sz=end-begin;
if(sz<1000) { while(begin!=end) sum+=*begin++; }
else {
mid=begin+sz/2;
auto handle=async([=]{ return parsum(begin,mid); });
sum+=parsum(mid, end);
sum+=handle.get();
}
return sum;
}
19
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Agenda
C++11
Factories (Virtual Constructors)
– Factories
– Clone
– Exemplars
Multi methods
22
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
The Number Example
Number
We have a hierarchy of
number types
inherits
Want to calculate with
Complex
Integer
Fraction
these types
(re,im)
i
(c:d)
Types are not known
during compile time => operation to be invoked must be
determined during run time
void solve_p2(Number p, Number q, Number s[2]) {
Number t=sqrt(p*p*fraction(1,4)-q);
s[0]=p*fraction(1,2)-t;
s[1]=p*fraction(1,2)+t;
}
23
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Only use complex?
Exclusively use the complex data type
C = R × R, R = Q ∪ I, Q = Z × Z
Nice idea BUT
– double ≠ R
– Is there a number type in C++ that is a superset of all other
number types? Is it possible to implement such a type?
– Efficiency
24
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Methods
We have different data types: complex, fraction, …
Problem:
– operator+/-/*/… should not be virtual
– And even if you don‘t care the code will really look terrible
Hence, we implement our own methods: add/sub/mul/…
– The real method to invoke (complex * complex or complex * fraction, etc.)
will be determined during run time
– Problem, only works with pointers
number* p2(number *x, number *p, number *q) {
return x->mul(x)->add(x->mul(p))->add(q);
}
25
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Methods
We have different data types: complex, fraction, …
Problem:
Beides durch
– operator+/-/*/… should not be virtual
– And even if you don‘t care the code will einen
really Wrapper
look terrible
lösbar!
Hence, we implement our own methods: add/sub/mul/…
– The real method to invoke (complex * complex or complex * fraction, etc.)
Memory
will be determined during run time
leak?!?
– Problem, only works with pointers
Unbequem!!!
number* p2(number *x, number *p, number *q) {
return x->mul(x)->add(x->mul(p))->add(q);
}
26
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Numbers: The Wrapper
class Number {
protected:
number *n; int *ctr;
public:
Number(number *nbr): n(nbr), ctr(new int(1)) {}
Number(const Number &nbr):n(nbr.n),ctr(nbr.ctr) { ++*ctr; }
~Number() { if(--*ctr==0) { delete n; delete ctr; } }
Number &operator=(const Number &b) {
if(--*ctr==0) { delete n; delete ctr; }
n=b.n;
ctr=b.ctr;
++*ctr;
return *this;
}
// …
27
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Implementation with Virtual Methods
class fraction: public number {
public:
fraction(int cntr=0, int denom=1)
: c(cntr), d(denom), os(NULL) {}
virtual Number add(Number n2) const {
complex *c2;
fraction *f2;
if((f2=dynamic_cast<fraction*>(n2.n))!=NULL) {
return new fraction((*this)+(*f2));
} else if ((c2=dynamic_cast<complex*>(n2.n))!=NULL) {
complex c1(static_cast<double>(*this));
return new complex(c1+(*c2));
} else { throw ...; }
}
// …
};
28
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Methods? (cont‘d)
Real Problems
– New data type
– New Operation
29
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Agenda
C++11
Factories (Virtual Constructors)
– Factories
– Clone
– Exemplars
Multi methods
30
–How can factories be implemented in C++
–How can we efficiently initialize a library/etc. in
C++?
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Numbers: Factories (Virtual Constructor)
Why?
– Want to create object from data describing the object
– Type of object depends on the data itself
Example
– Parse in different
number types
– Number *n = new
Number("(1:2)");
31
Number
inherits
Complex
Integer
Fraction
(re,im)
i
(c:d)
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Constructors: Factory (Usage)
main.cc
#include "NumberFactory.h"
#include "fraction.h"
32
int main(int argc, char *argv[]) {
Number n1=NumberFactory::make("(1:2)");
Number n2=NumberFactory::make("(1,2)");
cout << n1+n2 << endl;
}
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Constructors: Factory
typedef number* make_t(const char *);
NumberFactory.h
class NumberFactory {
static list<make_t*> cl;
public:
static void add(make_t *m) { cl.push_back(m); }
static Number make(const char *nbr) {
Number *r=NULL;
list<make_t*>::const_iterator b=cl.begin(), e=cl.end();
while(b!=e && (r=(*b)(nbr))==NULL) ++b;
return Number(r);
}
};
template<class T> class NumberFH { public:
NumberFH(make_t *m=(make_t*)&T::make) {
NumberFactory::add(m); }
};
33
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
number.h
class fraction : public number {
public:
fraction.cc
class number {
public:
virtual ~number() {}
};
fraction.h
Virtual Constructors: Factory (cont‘d)
34
// make can also be protected => factory must be friend
// of this class.
static fraction *make(const char *nbr);
};
#include "NumberFactory.h"
#include "number.h"
static NumberFH<fraction> register_fraction;
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Virtual Constructors: Factory (cont‘d)
number.o
cl
number
inherits
35
complex
integer
fraction
complex
::make
integer
::make
fraction
::make
complex.o
integer.o
fraction.o
© 2013 IBM Corporation
Virtual Constructors: Exemplars
class Exemplar {};
class Number {
static list<Number *>cl;
public:
Number.h
Not for the exam – Virtual Constructors as introduced by Coplien
IBM Research – Zurich
Business Integration Technologies
36
Number(Exemplar) { cl.push_back(this); }
virtual ~Number() {}
virtual Number *make(const char *nbr)=0;
static Number *make_nbr(const char *nbr) {
Number *r=NULL;
list<Number*>::const_iterator b=cl.begin(), e=cl.end();
while(b!=e && (r=b->make(nbr))==NULL) ++b;
return r;
}
};
© 2013 IBM Corporation
Fraction.h
Virtual Constructors: Exemplars (cont‘d)
class Fraction: public Number {
public:
Fraction(Exemplar dummy) : Number(Exemplar()) {}
Fraction *make(const char *nbr);
};
#include "Fraction.h"
Fraction.cc
Not for the exam – Virtual Constructors as introduced by Coplien
IBM Research – Zurich
Business Integration Technologies
37
static Fraction *exemplar=new Fraction(Exemplar());
Fraction *Fraction::make(const char *nbr) {
// If nbr points to a valid fraction, create
// a Fraction object and return it.
// If not, return NULL.
}
// …
© 2013 IBM Corporation
Not for the exam – Virtual Constructors as introduced by Coplien
IBM Research – Zurich
Business Integration Technologies
Virtual Constructors: Exemplars (cont‘d)
number.o
cl
Number
inherits
Complex
38
Integer
Fraction
Complex
*exempla
r
Integer
*exempla
r
Fraction
*exempla
r
complex.o
integer.o
fraction.o
© 2013 IBM Corporation
Virtual Constructors: Exemplars (Usage)
#include "Number.h"
#include “fraction.h"
main.cc
Not for the exam – Virtual Constructors as introduced by Coplien
IBM Research – Zurich
Business Integration Technologies
39
int main(int argc, char *argv[]) {
Number *n1=Number::make_nbr("(1:2)");
Number *n2=Number::make_nbr("(1,2)");
cout << (*n1)+(*n2) << endl;
}
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Factories: Summary
Table that contains a list of (member) functions that creates
other objects
Table is created through “special” constructors
=> No initialization necessary in the main function
!Attention!
Construction of table depends on the link order of the
object files. The type of object created should not depend
on this. Write clean code.
40
© 2013 IBM Corporation
Not for the exam – clone sometimes considered as Virtual Constructors
IBM Research – Zurich
Business Integration Technologies
Virtual Constructor (clone)
Constructors cannot be virtual themselves
Only methods and destructors may be virtual
Solution: Implement a virtual method that invokes the
constructor
class Number {
public:
virtual Number *clone()=0;
};
class Integer: public Number {
public:
virtual Integer *clone() { return new Integer(*this); }
};
41
© 2013 IBM Corporation
Not for the exam – clone sometimes considered as Virtual Constructors
IBM Research – Zurich
Business Integration Technologies
Virtual Constructors: new
Overload the new Operator
Problems
– Object to be created is not known a-priori
– Required memory space is not known either
Solution
– New memory allocator that does not change the address of the object
during a realloc
Details?
– See Jim Coplien. Advanced C++ Programming Styles and Idioms.
Addison-Wesley.
42
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Literature
Jim Coplien. Advanced C++ Programming Styles and
Idioms. Addison-Wesley.
43
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Agenda
C++11
Factories (Virtual Constructors)
– Factories
– Clone
– Exemplars
Multi methods
–C++ can be used in many different ways
–Very static with templates
–Very dynamic as this discussion has shown
–Makes C++ suitable to integrate programming
languages that follow different paradigms
44
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Multi Methods (Sometimes referred to as Multi Dispatch)
Operator depends on multiple arguments
(not only the this “argument”)
It should be possible to add functions posteriori
Solution
– Use a function table
– Invoke the function based on the types of arguments
45
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Multi Methods, finding the method
class Number {
protected:
static map<opdesc,op_t*> ops;
public:
// …
Describes name of function and argument types
// function types
// methods to register new functions
//
Number operator+(const Number &b) const {
op_t *op=ops[opdesc('+',typeid(*n),typeid(*(b.n)))];
if(op==NULL) throw runtime_error();
return Number(op(n,b.n));
}
// ...
};
46
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Multi Methods: Definition of Function Table
class Number {
protected:
struct opdesc {
char op;
const type_info *a1, *a2;
opdesc(char o, const type_info &arg1,
const type_info &arg2) : op(o), a1(&arg1), a2(&arg2) {}
bool operator==(const opdesc &o) const {
return op==o.op && (*a1)==*(o.a1) && (*a2)==*(o.a2);
}
bool operator<(const opdesc &o) const {
// define a < relation between opdescs
}
};
static map<opdesc,op_t*> ops;
// …
47
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Multi Methods: Registration of new functions
class Number {
public:
// …
typedef number *(op_t)(const number*,const number*);
static void register_op(char opname, const type_info &arg1,
const type_info &arg2, op_t *op) {
ops[opdesc(opname,arg1,arg2)]=op;
}
Number operator+(const Number &b) const {
op_t *op=ops[opdesc('+',typeid(*n),typeid(*(b.n)))];
if(op==NULL) throw runtime_error();
return Number(op(n,b.n));
}
// …
};
48
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Multi Methods: Summary
1. Definition of a “two-dimensional” function table
2. Wrapper for +/-/*/… operators that identifies actual function
based on function table
3. Registration of the functions like it is done for the factory
New data type?
– Create a new subclass of number
– Register its methods in the function table (ops)
New operator?
– Just register the new methods in the function table (ops)
49
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Summary
C++11
Factories (Virtual Constructors)
– Factories
– Clone
– Exemplars
Multi methods
50
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Exercise 1
Improve the computer player of your “Connect 4” implementation and make
sure you can accommodate computer players from your colleagues. Get at
least 3 computer players from other colleagues and see who is better. In
order to be able to do this you need to do the following:
– You need to implement a class religiously implementing the playfield interface that
gives the computer player access to the playfield through the stoneat(x,y)
function.
– Your computer player needs to implement the player interface that provides
theplay(playfield) method. In case the functionality provided by the playfield
interface is not sufficient, your player needs to convert the playfield into your own
representation.
– Make sure that your program works in such a way that two computer players can
play against each other.
– Do not change the playfield or player interfaces or otherwise your implementation
will not work with your colleagues’ implementations.
51
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Exercise 2
Compute gcf as Template-Meta-Program and with constexpr
Implement the greatest common factor (use Euclid’s algorithm)
as a template meta program and using constexpr functions (as
we did in the last lecture for primes).
52
© 2013 IBM Corporation
IBM Research – Zurich
Business Integration Technologies
Questions?
No more questions, then see you next week
53
© 2013 IBM Corporation