1 Advance Patterns and Frameworks Frameworker's Dilemma Peter Sommerlad, SS2005.
Simple C++ (Vol.2)Contact Info: Prof. Peter Sommerlad phone: +41 55 222 4984email: [email protected]...
Transcript of Simple C++ (Vol.2)Contact Info: Prof. Peter Sommerlad phone: +41 55 222 4984email: [email protected]...
Computer Science
Simple C++ (Vol.2)simpler generic & library code through better C++11 usage
ACCU 2012, Oxford, UK
slides: http://wiki.hsr.ch/PeterSommerlad/
Prof. Peter SommerladDirector IFS Institute for SoftwareOxford, 26th of April 2012
Donnerstag, 26. April 12
Contact Info: Prof. Peter Sommerladphone: +41 55 222 4984
email: [email protected]
LinticatorLinticator gives you immediate feedback on programming style and common programmer mistakes by integrating Gimpel Software’s popular PC-lint and FlexeLint static analysis tools into Eclipse CDT.PC-lint and FlexeLint are powerful tools, but they are not very well integrated into a modern developer's workflow. Linticator brings the power of Lint to the Eclipse C/C++ Development Tools by fully integrating them into the IDE. With Linticator, you get continuous feedback on the code you are working on, allowing you to write better code.
• Automatic Lint ConfigurationLint's configuration, like include paths and symbols, is automatically updated from your Eclipse CDT settings, freeing you from keeping them in sync manually.
• Suppress Messages EasilyFalse positives or unwanted Lint messages can be suppressed directly from Eclipse, without having to learn Lint's inhibition syntax–either locally, per file or per symbol.
• Interactive “Linting” and Information DisplayLint is run after each build or on demand, and its findings are integrated into the editor by annotating the source view with interactive markers, by populating Eclipse’s problem view with Lint’s issues and by linking these issues with our Lint Documentation View.
• Quick-Fix Coding ProblemsLinticator provides automatic fixes for a growing number of Lint messages, e.g, making a reference-parameter const can be done with two keystrokes or a mouse-click.
Register at http://linticator.com if you want to try it for 30 days or order via email. Linticator is available for Eclipse CDT 3.4 (Ganymede), 3.5 (Helios) and later. It is compatible with Freescale CodeWarrior.
see more on http://linticator.com
Pricing for Linticator is CHF 500.- per user (non-floating license). A maintenance contract that is required for updates costs 20% of license fee per year. The compulsory first maintenance fee includes 6 month of free updates.Orders, enquiries for multiple, corporate or site licenses are welcome at [email protected].
Linticator requires a corresponding PC-Lint (Windows) or FlexeLint license per user.
IFS Institute for SoftwareIFS is an institute of HSR Rapperswil, member of FHO University of Applied Sciences Eastern Switzerland.
In January 2007 IFS became an associate member of the Eclipse Foundation.
The institute manages research and technology transfer projects of four professors and hosts about a dozen assistants and employees. http://ifs.hsr.ch/
IFS INSTITUTE FOR SOFTWARE! HSR Hochschule für Technik, Oberseestrasse 10, CH - 8640 Rapperswil! http://ifs.hsr.ch
Contact Info: Prof. Peter Sommerladphone: +41 55 222 4984
email: [email protected]
Includator#include Structure Analysis and Optimization for C++ for Eclipse CDTThe Includator plug-in analyzes the dependencies of C++ source file structures generated by #include directives, suggests how the #include structure of a C++ project can be optimized and performs this optimization on behalf of the developer. The aim of these optimizations is to improve code readability and quality, reduce coupling and thus reduce duration of builds and development time of C++ software.
Includator Features• Find unused includes
Scans a single source file or a whole project for superfluous #include directives and proposes them to be removed. This also covers the removal of #include directives providing declarations that are (transitively) reachable through others.
• Directly include referenced filesIgnores transitively included declarations and proposes to #include used declarations directly, if they are not already included. This provides an “include-what-you-use” code structure.
• Organize includesSimilar to Eclipse Java Development Tool's Organize imports feature for Java. Adds missing #include directives and removes superfluous ones.
• Replace includes with forward declarationsLocates #include directives for definitions that can be omitted, when replacing them with corresponding forward declarations instead. This one is useful for minimizing #includes and reducing dependencies required in header files.
• Static code coverageMarks C++ source code as either used, implicitly used or unused by transitively following C++ elements’ definitions and usages. This helps to trim declarations and definitions not used from your source code. In contrast to dynamic code coverage, such as provided by our CUTE plug-in (http://cute-test.com) it allows to determine required and useless C++ declarations and definitions instead of executed oder not-executed statements.
• Find unused filesLocates single or even entangled header files that are never included in the project’s source files.
User Feedback and ParticipationIncludator is in beta testing. Register at http://includator.com if you are interested in a 30-day trial license or if you want to be notified about Includator’s release.
see more on http://includator.comto be released 2012
Individual licensing TBA. Free 30-day trial licenses available by registering at http://includator.com/account/register.
Enquiries for corporate or site licenses are welcome at [email protected].
IFS INSTITUTE FOR SOFTWARE! HSR Hochschule für Technik, Oberseestrasse 10, CH - 8640 Rapperswil! http://ifs.hsr.ch
#
Get Swiss Quality
Contact Info: Prof. Peter Sommerlad+41 55 222 4984email: [email protected]
Green Bar for C++ with CUTEEclipse plug-in for C++ unit testing with CUTEAutomated unit testing improves program code quality, even under inevitable change and refactoring. As a side effect, unit tested code has a better structure. Java developers are used to this because of JUnit and its tight integration into IDEs like Eclipse. We provide the modern C++ Unit Testing Framework CUTE (C++ Unit Testing Easier) and a corresponding Eclipse plug-in. The free CUTE plug-in features:
• wizard creating test projects (including required framework sources)
• test function generator with automatic registration
• detection of unregistered tests with quick-fix for registration
• test navigator with green/red bar (see screen shots to the right)
• diff-viewer for failing tests (see screen shot down to the right)
• code coverage view with gcov (see screen shot below)
Support for TDD and Mock Objects (Mockator)The CUTE plug-in incorporates support for Test-Driven Development (TDD) in C++. It will support code generation for test doubles and mock objects in spring 2012:
• create unknown function, member function, variable, or type from its use in a test case as a quick-fix (see screen shots below)
• move function or type from test implementation to new header file. (More MOVE Refactorings are becoming available in spring 2012)
• toggle function definitions between header file and implementation file, for easier change of function signature, including member functions (now part of CDT itself)
• extract template parameter for dependency injection, aka instrumenting code under test with a test stub through a template argument (instead of Java-like super-class extraction)
• automatic generation of test stubs and mock classes from test cases (spring 2012)
• extract super-class for dependency injection (spring 2012)
IFS Institute for SoftwareIFS is an Institute of HSR Rapperswil, member of FHO University of Applied Sciences Eastern Switzerland.In January 2007 IFS became an associate member of the Eclipse Foundation. The institute manages research and technology transfer projects of four professors and hosts a dozen assistants and employees. http://ifs.hsr.ch/
Eclipse update site for installing the free CUTE plug-in: http://cute-test.com/updatesite
IFS INSTITUTE FOR SOFTWARE HSR Hochschule für Technik, Oberseestrasse 10, CH - 8640 Rapperswil! http://ifs.hsr.ch
Get Swiss Quality
Contact Info: Prof. Peter Sommerlad+41 55 222 4984email: [email protected]
SConsolidatorEclipse CDT plug-in for SConsSCons (http://www.SCons.org/) is an open source software build tool which tries to fix the numerous weaknesses of make and its derivatives. For example, the missing automatic dependency extraction, make’s complex syntax to describe build properties and cross-platform issues when using shell commands and scripts. SCons is a self-contained tool which is independent of existing platform utilities. Because it is based on Python a SCons user has the full power of a programming language to deal with all build related issues.
However, maintaining a SCons-based C/C++ project with Eclipse CDT meant, that all the intelligence SCons puts into your project dependencies had to be re-entered into Eclipse CDT’s project settings, so that CDT’s indexer and parser would know your code’s compile settings and enable many of CDT’s features. In addition, SCons’ intelligence comes at the price of relatively long build startup times, when SCons (re-) analyzes the project dependencies which can become annoying when you just fix a simple syntax error.
SConsolidator addresses these issues and provides tool integration for SCons in Eclipse for a convenient C/C++ development experience. The free plug-in features:
• conversion of existing CDT managed build projects to SCons projects• import of existing SCons projects into Eclipse with wizard support• SCons projects can be managed either through CDT or SCons
• interactive mode to quickly build single source files speeding up round trip times• a special view for a convenient build target management of all workspace projects
• graph visualization of build dependencies with numerous layout algorithms and search and filter functionality that enables debugging SCons scripts.
• quick navigation from build errors to source code locations
More information:
http://SConsolidator.com/
Install the free SConsolidator plug-in from the following Eclipse update site:
http://SConsolidator.com/update
SConsolidator has been successfully used to import the following SCons-based projects into Eclipse CDT:
• MongoDB
• Blender
• FreeNOS
• Doom 3
• COAST (http://coast-project.org)
IFS INSTITUTE FOR SOFTWARE HSR Hochschule für Technik, Oberseestrasse 10, CH - 8640 Rapperswil! http://ifs.hsr.ch!
!
!
© Peter Sommerlad
2
Peter [email protected] Credo:
Work Areas
Refactoring Tools (C++, Scala, ...) for Eclipse
Decremental Development (make SW 10% its size!)
Modern Software Engineering
Pattern Books (co-author)
Pattern-oriented Software Architecture Vol. 1
Security Patterns
Background
Diplom-Informatiker / MSc CS (Univ. Frankfurt/M)
Siemens Corporate Research - Munich
itopia corporate information technology, Zurich
Professor for Software Engineering, HSR Rapperswil, Director Institute for Software
People create Software
communication
feedback
courage
Experience through Practice
programming is a trade
Patterns encapsulate practical experience
Pragmatic Programming
test-driven development
automated development
Simplicity: fight complexity
Donnerstag, 26. April 12
© Peter Sommerlad
A Quick Reality Check - please raise your hands
I prefer using STL algorithms over loops.
I am familiar with the Boost library collection.
I have provided some of the Boost libraries
I've memorized Andrej Alexandrescu's "Modern C++ Design"
I've read the new ISO C++11 standard
I wrote parts of the ISO C++ standard
I know most of the ISO C++ standard by heart (not me :-)
3
Donnerstag, 26. April 12
© Peter Sommerlad
Outline (Part 2)
Move Semantics - do I need to care?
overflow/some overlap part 1
Literal types and constexpr
User-defined Literals
Simple (variadic) templates
recursion
sizeof...
static_assert
local classes as template parameters
Demo Mockator: usage
Regular Expressions
not yet ready in g++ 4.7.0 lib
Simpler generics
auto and return types
decltype
type traits
Simple concurrency: async
4
Donnerstag, 26. April 12
© Peter Sommerlad
Move Semantics - Do I need to care? -> Usually not!
In non-library code you might not need to care at all, things just work!
often you do not need to care! Only (library) experts need to.
for elementary (aka trivial) types move == copy anyway
R-Value-References allow optimal "stealing" of underlying object content
copy-elision by compilers does this today for many cases already
e.g., returning std::string or std::vector
Type&& denotes an r-value-reference: reference to a temporary object
std::move(var) denotes passing var as rvalue-ref and after that var is "empty"
if used as argument selects rvalue-ref overload, otherwise using var would select lvalue-ref overload or const-ref overload
like with const &, rvalue-ref && bound to a temporary extends its lifetime
R-value references are also serving a second purpose: perfect forwarding
see std::forward() - that actually does nothing, except avoiding unnecessary copies and provides the correct overloads of a called function, based on your callers arguments
only needed in library/generic code dealing with passing arguments through
5
Donnerstag, 26. April 12
© Peter Sommerlad
New Value Terminology in the Standard - rvalue-References
lvalue - "left-hand side of assignment" - can be assigned to
glvalue - "general lvalue" - something that can be changed
rvalue - "right-hand side of assignment" - can be copied
prvalue - "pure rvalue" - return value, literal
xvalue - "eXpiring value - object at end of its lifetime" - can be pilfered - moved from
rvalue-references refer to temporaries or pilfer-able variables
6
c� ISO/IEC N3290
4 There is a partial ordering on cv-qualifiers, so that a type can be said to be more cv-qualified than another.Table 9 shows the relations that constitute this ordering.
Table 9 — Relations on const and volatileno cv-qualifier < constno cv-qualifier < volatileno cv-qualifier < const volatile
const < const volatilevolatile < const volatile
5 In this International Standard, the notation cv (or cv1, cv2, etc.), used in the description of types, representsan arbitrary set of cv-qualifiers, i.e., one of {const}, {volatile}, {const, volatile}, or the empty set.Cv-qualifiers applied to an array type attach to the underlying element type, so the notation “cv T,” whereT is an array type, refers to an array whose elements are so-qualified. Such array types can be said to bemore (or less) cv-qualified than other types based on the cv-qualification of the underlying element types.
3.10 Lvalues and rvalues [basic.lval]1 Expressions are categorized according to the taxonomy in Figure 1.
����������
�� � ��� �
�� � ��� � ���� �
Figure 1 — Expression category taxonomy
— An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignmentexpression) designates a function or an object. [ Example: If E is an expression of pointer type, then*E is an lvalue expression referring to the object or function to which E points. As another example,the result of calling a function whose return type is an lvalue reference is an lvalue. — end example ]
— An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that itsresources may be moved, for example). An xvalue is the result of certain kinds of expressions involvingrvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvaluereference is an xvalue. — end example ]
— A glvalue (“generalized” lvalue) is an lvalue or an xvalue.— An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment
expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associatedwith an object.
— A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a functionwhose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true isalso a prvalue. — end example ]
Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue,or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in
§ 3.10 78
Type & Type && TypeType const &
Donnerstag, 26. April 12
© Peter Sommerlad
Move Semantic
Goal: no unnecessary object copies, transfer temporaries efficiently
Mechanisms:
r-value references: Type&&
move-ctors Type(Type&&), move-assignment operator=(Type&&)
deleted copy-ctor, copy assignment -> move-only type
std::move(lvalue) -> prepare lvalue(aka variable) to move from
relevant for classes that manage (expensive) internals and can hand those over
e.g. containers
relevant for classes that couldn't keep invariant if copied
e.g. std::unique_ptr, std::future, "single-ownership" objects
7
Donnerstag, 26. April 12
© Peter Sommerlad
Copy Elision works even before C++11
"normal" users can rely on good compiler technology
return by value is OK (even with C++03)
aka "return value optimization"
With moveable types, pass by value can be more efficient than pass by const&
subtle things happen, with pass by value a temporary gets moved into parameter
moving from a const& when a copy of the parameter is needed, doesn't work
If you do not explicitly design your own move-only/move-enabled types you usually do not need to care when using the standard library
8
Donnerstag, 26. April 12
© Peter Sommerlad
Example of Move Semantic with Move-only Type9
#include <iostream>struct MoveOnly{ MoveOnly() = default; MoveOnly(MoveOnly&&) { std::cout << "Move constructor called\n"; } MoveOnly(const MoveOnly&) = delete; // implicitly};void f(MoveOnly) { std::cout << "f(MoveOnly) called\n"; }void g(MoveOnly&&) { std::cout << "g(MoveOnly&&) called\n"; }void g(MoveOnly const &){ std::cout << "g(MoveOnly const&) called\n"; }int main(){ f( MoveOnly{} ); // rvalue temporary g( MoveOnly{} ); // rvalue temporary std::cout << "moving lvalues:\n"; MoveOnly mv{}; // lvalue //f(mv); // doesn't compile, lvalue cannot be passed f(std::move(mv)); // make an rvalue from lvalue g(mv); // binds to const-ref g(std::move(mv)); // binds to rvalue-ref}
Move constructor calledf(MoveOnly) calledg(MoveOnly&&) calledmoving lvalues:Move constructor calledf(MoveOnly) calledg(MoveOnly const&) calledg(MoveOnly&&) called
move ctor calls might be elided!as here:
f(MoveOnly) calledg(MoveOnly&&) calledmoving lvalues:Move constructor calledf(MoveOnly) calledg(MoveOnly const&) calledg(MoveOnly&&) called
Donnerstag, 26. April 12
© Peter Sommerlad
Move-enabling a class: DO NOT DO THAT YOURSELF!
If you implement a class that does its own resource management of large resources you might want to do your own copy and move implementation
first: resist! DON'T DO THAT! if you do not have performance issues with too many copies, everything is fine.
second: let standard library classes do the resource management for you
then, compiler generated member-wise copy and member-wise move is fine and fast!
never ever use malloc or new in your code again (new is only allowed to initialize a unique_ptr)
third: if you can prove your class gets copied too often you might try a simple version
only if that fails, learn all details about move-semantics and try yourself,
but be warned, it is very easy to get it wrong!
fourth: become a moveable-type expert first, before you roll your own!
I experimented, enabling move constructor and assignment can make things slower
(1.5 .. 3 times in my very simple examples)
10
Donnerstag, 26. April 12
© Peter Sommerlad
What to use to profit from move semantics?
If you pass an object x to a function foo that has an r-value-reference overload use std::move(x) as argument
that makes it an rvalue deliberately, you promise not to rely on x's content afterwards
11
struct X{};
//void foo(X v){ // ambiguous//std::cout << "foo(X) \n";//}void foo(X& lv){ // ref std::cout << "foo(X&) \n";}void foo(X&& rvr){ // rvalue ref std::cout << "foo(X&&) \n";}void foo(X const& rv){ // const ref std::cout << "foo(X const&) \n";}void foo(X const && rvr){//rvconst ref std::cout << "foo(X const &&) \n";}
int main(){ X x{}; // value X const &y=X{}; // const ref X &z=x; // reference X const a{}; // constant X &&b=X{}; // rvalue ref X const &&c=X{}; // const rv-ref
foo(x); foo(const_cast<X const&>(x)); foo(std::move(x)); foo(y); foo(std::move(y)); foo(z); foo(std::move(z)); foo(a); foo(std::move(a)); foo(b); foo(std::move(b)); foo(c); foo(std::move(c));}
foo(X&) foo(X const&) foo(X&&) foo(X const&) foo(X const &&) foo(X&) foo(X&&) foo(X const&) foo(X const &&) foo(X&) foo(X&&) foo(X const&) foo(X const &&)
output:
rvalue const ref (X const &&) is not very useful in practice!
Donnerstag, 26. April 12
© Peter Sommerlad
Defining classes!12
about 7 pages of rules for compiler provided copy/move ctor and destructor in the standard document.
It is very hard to know and apply them all correctly.
However, C++11 allows to use appropriate library stuff so that you do not need to care!
containers, strings, smart pointers
Write your classes in a way that you do not need to care
let the standard library provide all resource management for you!
std::string, std::vector and the other containers are your friends
use std::shared_ptr<X> if you intend to keep your class copyable and share the resource
keeps your class default copyable and moveable
use std::unique_ptr<Y> if you want to be the only one caring for your resources
this makes your class move-only, if you do not inhibit move-ctor/move-assignment otherwise
No more manual memory management needed, if done right
even better than in Java, because destruction is deterministic!
Donnerstag, 26. April 12
© Peter Sommerlad
Literal Types - what for?
C++ wants to allow user-defined class types behave similarly and with equal efficiency than built-in types
so far syntactical equivalence was given, but you couldn't define a type with a constructor that would be evaluated at compile time, e.g., to initialize static data (pre C++11)
Literal types in C++11 allow to define types which can be guaranteed initialized or computed with at compile time.
Now it is possible to create your own class-based types that work like int!
e.g., std::complex<double> is now a literal type, compile time constants possible!
Key mechanism: constexpr
constexpr constructors
trivial destructor (one that is provided by the compiler)
only members of literal type
everything that would require run-time memory allocation, e.g., std::string is not allowed!
but a bit more than with just trivial types
13
Donnerstag, 26. April 12
© Peter Sommerlad
constexpr functions
if called with constants must be able to evaluate a constant at compile time
all parameters and return type must be literal types (relaxed for templates)
just a single return statement (but can use recursion!)
14
constexpr int squarei(int i){ using namespace std; // allowed return i * i;}
int main(){ constexpr int i{42}; // compile time constant const int j{i}; // could be initialized at run time constexpr int k{squarei(j)}; char s[squarei(j)]; std::cout << " i = "<< i << " j = " << j << " k = "<< k << "\n";
std::cout << "sizeof s = "<< sizeof(s)<< "\n"; int l{squarei(2)};//constexpr int m{squarei(l)}; // not allowed const int n{squarei(l)}; // allowed initialized at run-time std::cout << "square(l) = "<< squarei(l) << " n = " << n << "\n";
i = 42 j = 42 k = 1764sizeof s = 1764square(l) = 16 n = 16
output:
Donnerstag, 26. April 12
© Peter Sommerlad
constexpr function example: compile-time fibonacci
You can use recursion and conditional evaluation:
but do not stress your compiler too much!
15
constexpr unsigned long long fib(unsigned long long i){ return (i>2)?fib(i-1)+fib(i-2) :(i>0?1:0);}
int main(){ constexpr auto f=fib(42); std::cout << "fib(42) = " << f <<"\n"; constexpr auto g=fib(5); std::cout << "fib(5) = " << g <<"\n";}
fib(42) = 267914296fib(5) = 5
output:
Donnerstag, 26. April 12
© Peter Sommerlad
trivial and literal types
user-defined trivial types == C-struct (more or less)
Literal types allow for guaranteed compile-time initialization
but have restrictions on what you can actually do at compile time
but you get encapsulation plus compile time initialization!
16
struct trivial { int x,y;};constexpr trivial y{1,2};
struct non_trivial{ non_trivial(int x,int y) :x{x},y{y}{}private: int x,y;};// doesn't compile//constexpr non_trivial x{4,2};static const non_trivial v{3,1};// initialized (may be) at run time
struct Coord { constexpr Coord(int x, int y):x{x},y{y}{} constexpr int getx()const{return x;} constexpr int gety()const{return y;} constexpr Coord mirrorx()const{return Coord{x,-y};} //constexpr Coord transpose(){ // return (std::swap(x,y), *this); // } // swap is not constexpr Coord transpose(){ return (std::swap(x,y), *this);}private: // not allowed in trivial types int x,y;};constexpr Coord p{1,2};constexpr int i{p.getx()};
A literal type:
Donnerstag, 26. April 12
© Peter Sommerlad
UDL User-Defined Literals - why?
Literals without dimension can be confusing in some domains
miles vs. kilometers
speed in mph, km/h, mach or c units
String literals in C++ aren't std::strings
problem with
auto s="hello";
It would be nice to spell out complex numbers like
auto c=2_r+1_i; auto d=1_il+1.0l;
Or even to have binary literals in program code
(for the younger ones who no longer can read octal :-)
17
Donnerstag, 26. April 12
© Peter Sommerlad
UDL example: literals for lengths18
namespace lengths_in_meter {// norm everything to metersconstexprlong double operator"" _feet(long double d){ return d*0.3048;}constexprlong double operator"" _feet(unsigned long long d){ return d*1.0_feet;}constexprlong double operator"" _yard(long double d){ return d*3_feet;}// and so on...} // lengths_in_meter
void testYardsAndFeet(){ using namespace lengths_in_meter; ASSERT_EQUAL_DELTA(0.9144_m,1_yard,0.00001); ASSERT_EQUAL_DELTA(0.9144_m,1e0_yard,0.00001); ASSERT_EQUAL(1_yard,3_feet);}void testKmAndMiles(){ using namespace lengths_in_meter; ASSERT_EQUAL(1000.0_m,1_km); ASSERT_EQUAL_DELTA(1609.344_m,1_mi,0.0001); ASSERT_EQUAL(100.0_m,0.1_km);}
Donnerstag, 26. April 12
© Peter Sommerlad
Specifying dimensions with UDL operator""
Put your own UDL operators in a namespace
lookup is always unqualified, but you want to use short names that might easily conflict
this is a situation where a local using namespace is allowed
if mixing dimensions choose one common dimension, e.g., meters for lengths
may be even put that meta information into the namespace's name
If defining UDL operator"" for numeric values, you often want to overload both versions taking numbers and make it constexpr
operator"" _km(long double)
operator"" _km(unsigned long long)
but then return the same type, unless you want to do something specific for integral values
UDL names must start with an underscore '_'
and when defining operator"" you need a space between "" and _udl
19
Donnerstag, 26. April 12
© Peter Sommerlad
Problem: auto with "string literals"
What is the type of s?
auto s="hello";
my solution:
yes, it is a std::string!
but wait, why not overload?
well, that one is only for numbers:
20
// cannot be constexpr, string not literal typestd::string operator"" _str(char const *s,size_t l){ return std::string(s,l);}
void testStringLiteral(){ auto s="hallo"_str; ASSERT_EQUAL("hallo",s); ASSERT_EQUAL(5,s.length());}
std::string operator"" _str(char const *s){ return std::string(s);} void testQuoteLessStringLiteral(){
auto s=123_str; ASSERT_EQUAL("123",s); //auto t=hallo_str; // doesn't work=identifier auto u=1.234_str; ASSERT_EQUAL("1.234",u);}
Donnerstag, 26. April 12
© Peter Sommerlad
auto with complex numbers without std::complex<long double>...
Wouldn't it be nice to be able to write:
Well, that is possible:
21
auto d = 1_il + 1.0l; // std::complex<long double>{1.0,1.0} auto c = 1_i + 1_r; // std::complex<double>{1,1} c -= 1_i; ASSERT_EQUAL(1.0,c.real()); ASSERT_EQUAL(0.0,c.imag()); ASSERT_EQUAL(1.0l,d.imag());
namespace mycomplex{constexprstd::complex<long double> operator"" _il(long double d){ return std::complex<long double>{0,d};}constexprstd::complex<long double> operator"" _il(unsigned long long d){ return std::complex<long double>{0,static_cast<long double>(d)};}constexprstd::complex<long double> operator"" _rl(long double d){ return std::complex<long double>{d,0};}// and so on...} // mycomplex
Donnerstag, 26. April 12
© Peter Sommerlad
What about binary literals...
Wouldn't it be nice to write something like:
a solution (partly inspired by Paul Preney, see here)
use a UDL operator that is a variadic template taking char...
the compiler will use anything in front of "_bits" as the template argument
to actually calculation we need to recurse with an type template bitsImpl<> at compile time
22
void testBinaryLiterals() { char a[100_bits]; // 4 elements - compile time computed! ASSERT_EQUAL(4,sizeof(a)); ASSERT_EQUAL(32ull,100000_bits);//1234_bits; // will trigger static_assert}
template <char... Digits>constexpr unsigned long long operator"" _bits(){ return bitsImpl<Digits...>::value;}
Donnerstag, 26. April 12
© Peter Sommerlad
calculating the value of binary literals at compile time
we start out with a forward declaration:
when there is a '0' in the front, nothing to do, cut it and ask for the remaining value:
when there is a '1' shift it left by the length of the remaining Digits... and or it with the value of the remaining digits:
we just need the generic one as a base case for recursion and check if there are any wrong digits left over to generate a nicer compile time error instead of silence
23
template <char... Digits>struct bitsImpl<'1',Digits...>{ static constexpr unsigned long long value= bitsImpl<Digits...>::value|(1ULL<<sizeof...(Digits));};
template <char... Digits>struct bitsImpl;
template <char... Digits>struct bitsImpl<'0',Digits...>{ static constexpr unsigned long long value=bitsImpl<Digits...>::value;};
// serves also as base case of recursiontemplate <char... Digits>struct bitsImpl{ static_assert(! sizeof...(Digits),"_bits must be 0 or 1"); static constexpr unsigned long long value=0;};
Donnerstag, 26. April 12
© Peter Sommerlad
What the hell is template <char... Digits> and Digits...?
Welcome to variadic templates!
consider it .../varargs, but for templates at compile time
great relief for template-meta-programming (who's doing that)
have a look at boost::bind()'s implementation to see what horror you get with variable number of arguments in template functions -> you need to specify all overloads manually or use preprocessor meta-programming to get that.
Problem: where to place ...?
at template parameter definition after typename or non-type paramter's type
template <typename...TYPES>
TYPES is now a "parameter pack"
at parameter pack usage (aka pack expansion) after the parameter pack's name
return std::tuple<TYPES...>{};
after sizeof... to obtain the number of elements in the parameter pack
sizeof...(Digits)
To actually do something useful it requires often recursive template specializations
do not forget the base case!
24
Donnerstag, 26. April 12
© Peter Sommerlad
A type-safe print(std::ostream&, ...)
printf(...) is horribly unsafe,
but out<<a<<b<<c<<d<<f; looks ugly! here is a potential solution:
25
// base case overloadvoid print(std::ostream &out) { out << "\n";}//variadic templatetemplate<typename Head, typename... Tail>void print(std::ostream &out, Head const& head, Tail const& ...tail) { out << head; if (sizeof...(tail)) { out << ", "; } print(out,tail...); //recurse on tail}void testVariadicPrint(){ std::ostringstream out{}; print(out,1,2,3,"hello",' ',"world"); ASSERT_EQUAL("1, 2, 3, hello, , world\n",out.str());}
cut-off head
Donnerstag, 26. April 12
© Peter Sommerlad
What is static_assert(b,msg)?
it is a compile-time assert
allows for nicer compile errors and for checking your code's assumptions about its environment
message is not optional and must be a string literal! (already an issue for the next std)
compilation fails if constexpr condition is false
useful for compile time checks, such as sizeof(unsigned)==4
especially useful with type traits that allow querying type information at compile time
26
// serves also as base case of recursiontemplate <char... Digits>struct bitsImpl{
static_assert(! sizeof...(Digits),"_bits must be 0 or 1"); static constexpr unsigned long long value=0;};
static_assert(sizeof(int) == 8,"int is not 64 bit");
static_assert(std::is_unsigned<char>::value,"char is signed");
Donnerstag, 26. April 12
© Peter Sommerlad
Local Classes as Template Arguments
That is now allowed. Template arguments no longer restricted to namespace-level types.
However, some restrictions still apply, e.g., they cannot have member templates!
Usage scenario: Test-Stub and Mock-Object Generation with Mockator
Little Demo
27
void testLoosingGame() { struct LoosingDie { int roll() const { return 1; } }; GameFourWinsT<LoosingDie> game; std::ostringstream out; game.play(out); ASSERT_EQUAL("You lost!\n",out.str());}
Donnerstag, 26. April 12
© Peter Sommerlad
TDD with CDT
TDD Refactoring
Unit Testing
Test-DrivenDevelopment
C++ CUTEwith Eclipse CDTin
and
CUTE http://cute-test.com - free!!!
simple to use - test is a function
understandable also for C programmers
designed to be used with IDE support
can be used without, but a slightly higher effort
deliberate minimization of #define macro usage
macros make life harder for C/C++ IDEs and forprogrammers
Donnerstag, 26. April 12
© Peter Sommerlad
Seams and Mocks
MockatorRefactoring Unit Testing
Seam Introduction
C++
Object SeamCompile Seam
Preprocessor SeamLink Seam
Legacy Code enabling
Test Double generation
Mock Object generation
Master Thesis by Michael Rüegginspired and supervised by Prof. Peter Sommerladalpha statushttp://sinv–56033.edu.hsr.ch/mockator/repo
Function Tracer generation
Donnerstag, 26. April 12
© Peter Sommerlad
Mockator Demo - Compile Seam using Templates
Extract Template Parameter
part of CUTE plug-in
Use Template in Test
introduce Mock object for DIE
create test double class...
add missing member function
implement test double code
Add Mock Object Support
check for expected calls (C++11)
additional features
dependency injection through
templates
abstract interface classes
30
Donnerstag, 26. April 12
© Peter Sommerlad
Mockator - Preprocessor Seam
mockator_malloc.h
mockator_malloc.c
Generating trace functions like this one is easy: Ctrl+Alt+T (on Linux)
Mockator passes mockator_malloc.h to the GNU compiler by using its -include option
31
#ifndef MOCKATOR_MALLOC_H_#define MOCKATOR_MALLOC_H_#include <cstdlib >int mockator_malloc(size_t size, const char *fileName, int lineNumber); #define malloc(size_t size) mockator_malloc((size),__FILE__,__LINE__)#endif
#include "mockator_malloc.h"#undef mallocint mockator_malloc(size_t size, const char * fileName, int lineNumber){//TODO your tracing code here return malloc(size);}
Donnerstag, 26. April 12
© Peter Sommerlad
Mockator - Link Seam - Shadowing & Wrapping Library Functions
Shadowing on Linux only using GCC Linker
Allows wrapping of functions in shared libraries
Both Linux and MacOS X supported
Mockator does all the hard work like
creating a shared library project,
adding dependencies to the dl library,
creating run-time configurations with the following env values, etc.,
Linux: LD PRELOAD=libName.so MacOS X:
DYLD FORCE FLAT NAMESPACE=1
DYLD INSERT LIBRARIES=libName.dylib
32
int foo(int i) { static void *gptr = nullptr; if(!gptr)gptr= dlsym(RTLD_NEXT,"_Z3fooi");typedef int (*fptr)(int); fptrmy_fptr= reinterpret_cast<fptr>(gptr); // TODO putyourcodehere return my_fptr(i);
}
Donnerstag, 26. April 12
© Peter Sommerlad
Regular Expressions (almost there, not yet in library of g++4.7.0
Demo: A simple grep implementation (requires clang++ and libstdc++):
33
#include <regex>#include <iostream>#include <sstream>// currently only works with clang++ and libstdc+++ not with g++ 4.7int main(int argc,char const *const *argv)try{ std::regex re(argv[1]); // doesn't work with g++4.7 yet std::string line; while(getline(std::cin,line)){ if (std::regex_search(line,re)) std::cout<<line<<std::endl; }}catch(std::exception &e){ std::cout << "caught exception..." << e.what() << " regex:"<<argv[1];}
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Generic Functions
Some simple generic functions have been hard to specify, e.g. square() when user-defined types might be used that overload operators in an interesting way.
trailing return type helps a bit, if function return type depends on arguments
For example, what if T defines operator*(T,T) returning something else than T?
Simpler Type Traits and Meta Functions
meta-function results are automatically considered types without ::type extractor
34
template <typename T>T square(T t){return t*t;}
Donnerstag, 26. April 12
© Peter Sommerlad
Problem: generic functions with multiple parameters
The following is a compile error, even though 5*0.5 is a valid expression
We can "fix" that with specifying providing two template parameters:
35
template <typename T>T mul(T t, T s){ return t*s;}
int main(){ auto j=mul(5,0.5); // compile error! std::cout << "j =" << j << "\n";}
template <typename T, typename U>T mul(T t, U u){ return t*u;}
int main(){ auto j=mul(5,0.5); std::cout << "j =" << j << "\n"; // what is the result?}
Donnerstag, 26. April 12
© Peter Sommerlad
using trailing return type specification with decltype
A better fix lets the compiler figure out the return type
unfortunately that requires a bit of code duplication
syntax inspired by lambdas, where it is often not needed, because it is deduced
could even be constexpr
36
template <typename T, typename U>auto mul(T t, U u)->decltype(t*u){ return t*u;}
int main(){ auto j=mul(5,0.5); std::cout << "j =" << j << "\n"; // what is the result?}
Donnerstag, 26. April 12
© Peter Sommerlad
Type queries and converters
Most of it previously defined by boost::type_traits already
some new stuff possible through compiler magic with C++11
A whole lot of type queries (too many to list)
very useful with typename template arguments
can be used with enable_if SFINAE tricks to select function template instantiations
Too much to discuss all
more to come...
a crazy example:
see also cute_equals.hfor more sane usages
37
#include <type_traits>#include <iostream>template <typename T>auto foo(T t)->typename std::make_unsigned<T>{ return std::make_unsigned<T>{};}template <typename META, typename T>auto bar(META m,T t)-> typename META::type{ return static_cast<typename META::type>(t);}int main(){ int const n=-5; auto m=foo(n); auto x=bar(m,n); std::cout << x << std::endl;}
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Concurrency
async and futures
thread
mutex, lock_guard and unique_lock
condition_variable
atomic<T>
thread_local storage class specifier
not all is yet implemented everywhere
some last-minute adjustments to the standard kept library implementors from adjusting
boost::thread allows to use many of the new standard (lower-level) features already on several platforms
38
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Concurrency
C++11 finally has a memory model that takes multi-threading and hardware parallelism into account
in addition to a language extension for thread-local variables and library support for low-level threading (thread, mutex, condition_variable) it provides an easy to use mechanism for asynchronous/parallel execution of a function
auto future_value=std::async(function, parameters);
function is started in parallel and future_value.get() obtains its result.
one can use it even within a single threaded environment
call is deferred until get() is called (std::launch::deferred as first parameter to async)
to force concurrent execution use std::launch::async as first parameter to async
Lambdas are a convenient way for applying std::async()
caution when capture is by reference, use copy-capture always instead
39
Donnerstag, 26. April 12
© Peter Sommerlad
A very simple example using async()40
#include <future>#include <iostream>#include <cmath>
double do_some_expensive_calculation(double input){! return std::sqrt(input); // simulate that}
int main(){! auto result=std::async(std::launch::async, do_some_expensive_calculation,81.0);! std::cout << "do some other useful things" << std::endl;! std::cout << "waiting for he result..." << std::endl;! std::cout << "the result is= "<< result.get()<< std::endl;}
Donnerstag, 26. April 12
© Peter Sommerlad
An async example
not very useful, but to show mechanism
41
#include <future> // defines async and future#include <iostream>#include <chrono>unsigned long long fibo_def(unsigned long long n){ if (n < 1) return 0; if (n < 2) return 1; auto f1 = std::async(fibo_def,n-1); // obtain future, eventually start thread auto f2 = std::async(fibo_def,n-2); // obtain future, eventually start thread return f1.get() + f2.get(); // use future's result}int main(int argc, char **argv){ if (argc < 2 || atoi(argv[1]) <1) { std::cout<< "Usage: "<< argv[0] << " number\n"; exit(1); } unsigned long long n=std::strtoull(argv[1],nullptr,10); using Clock=std::chrono::high_resolution_clock; using msec=std::chrono::milliseconds; Clock::time_point t0 = Clock::now(); // standard millisecond timing auto fibn=fibo_def(n); Clock::time_point t1 = Clock::now(); msec ms = std::chrono::duration_cast<msec>(t1 - t0); std::cout <<"fibo_def("<<n<<") = " << fibn<<" :" << ms.count() << "ms\n";}
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Concurrency - a note on futures
result of async is a std::future<result_type>
this cannot be copied, only moved, so no sharing is possible
allows for move-only result types
If the result needs to be used in several places and is copyable one can obtain a shared_future from async instead:
auto a_shared_future=std::async(function, parameters).share();you can call get() on a shared_future object multiple times and they will wait for the
result to become available.
42
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Low-level Concurrency - threads
First Rule: DO NOT USE THREADS and other low-level facilities!
you will get it wrong!
Many use POSIX-threads as C-library facilities in C++ code - DON'T! (even in C++03)
e.g., lock-unlock pairs are error-prone -> use RAII instead
C++11 provides std::lock_guard for that
std::thread provides thread abstraction
constructor and join() for forking and waiting-on other threads
std::thread t([]{ std::cout << " running parallel ";}); std::cout <<"main thread"; t.join();
before thread is destructed join() must be called on it (or detach()).
you can synchronize with mutexes and locks
43
Donnerstag, 26. April 12
© Peter Sommerlad
Simpler Low-Level Concurrency - lock_guard, unique_lock, call_once
Implement the Scoped-Locking idiom with std::lock_guard<mutex_type>
{ std::lock_guard<std::mutex> guard(theMutex); /* exclusive region */ ; }
For non-scoped locking consider using std::unique_lock<mutex_type>
made possible through "move-semantics", like unique_ptr for a lock
can be passed-to/returned-from functions to transfer ownership of lock
releases lock on destruction, if owned
only consideration is lifetime of wrapped mutex object must exceed uniqe_lock's lifetime
call_once() ensures that a function is only called by one out of many threads
static std::once_flag once; std::call_once(once, function, parameters);
once_flag is an opaque type, call_once works per once_flag instance.
convenient for lacy initialization/verification mechanisms that might be expensive
44
Donnerstag, 26. April 12
© Peter Sommerlad
Synchronization - Notification with std::condition_variable
std::condition_variable provides wait() for std::unique_lock<std::mutex>
thread must hold the lock when calling wait()
also variations including timing: wait_until() and wait_for()
all wait functions allow passing a predicate (bool function) as a condition
no external loop needed, wait returns when predicate becomes true or a timeout happens
notify_one() and notify_all() wake up threads blocked in wait()
spurious wakeups in wait() are allowed (need to check underlying predicate!)
45
Donnerstag, 26. April 12
© Peter Sommerlad
Low-low-level concurrency support: atomic<T>
C++11 atomics are designed to work together with C11 atomics
std::atomic<T> is a class template, however, interoperability with C11's atomics given
bool, integer types and pointers must be defined template specializations, others usually don't work
free functions and corresponding C-types allow intermixing C and C++ with same atomic variables
initialization of an atomic variable is non-atomic
all other defined operations are atomic
implementations can provide lock-free (aka fast) atomic implementations
only std::atomic_flag must be lock-free (a special version of std::atomic<bool>)
memory-order can be specified to further optimize code using atomics
46
Donnerstag, 26. April 12
© Peter Sommerlad
Thread Support on the Language Level: thread_local
a new "storage class" keyword can ensure that each thread gets its own version of a (global) variable. (thread_local static and thread_local extern make sense)
thread_local doesn't make sense for parameters or local variables allocated on the stack
thread_local variables live for the lifetime of a thread and are destructed, before it can be join()-ed. << need to check that, standard unclear wrt "thread exits"
thread_local variables have C++'s deterministic life-time guarantee. This raised heavy discussion on how to implement thread pools, where threads are recycled: should logically the thread_locals be deleted and re-created each time a thread from the pool is used? --> this is not resolved and if you use a thread pool, you cannot assume that when you hand a function to a thread in the pool to execute that the thread_local variables have an initial value.
thread_local on a local variable within a block implies static
thread_local can only applied to class members that are static member variables
47
Donnerstag, 26. April 12
© Peter Sommerlad
Questions ?
http://cute-test.com (Mockator will be here 3.Q2012)
http://linticator.com http://includator.com
http://sconsolidator.com (M. Rüegg as well)
[email protected] http://ifs.hsr.ch
48
Have Fun with C++ TDD, Mockator and
Refactoring!
Donnerstag, 26. April 12