On the development of C++ On the development of C++ Practice and - - PowerPoint PPT Presentation

on the development of c on the development of c
SMART_READER_LITE
LIVE PREVIEW

On the development of C++ On the development of C++ Practice and - - PowerPoint PPT Presentation

1979 => B.Stroustrup: Adding Classes to C . in Software On the development of C++ On the development of C++ Practice and Experience, Feb, Game Engine Architecture Game Engine Architecture 1983, pp. 139-161. 1998 ISO C++ Standard


slide-1
SLIDE 1

Game Engine Architecture Game Engine Architecture Spring 2017 Spring 2017

  • 1. Modern C++ (11/14) for Game Engines
  • 1. Modern C++ (11/14) for Game Engines
  • 1. Modern C++ (11/14) for Game Engines
  • 1. Modern C++ (11/14) for Game Engines

Juha Vihavainen Juha Vihavainen University of Helsinki University of Helsinki [Gregory, Ch. 3 [Gregory, Ch. 3 Fundamentals of SE for Games Fundamentals of SE for Games ] ] [Gregory, Ch. 3 [Gregory, Ch. 3 Fundamentals of SE for Games Fundamentals of SE for Games ] ] [Josuttis, Ch. 3 [Josuttis, Ch. 3 New Language Features New Language Features ] ] [ [Lakos Lakos, , Large Large-

  • Scale C++ Software Design

Scale C++ Software Design ] ]

On the development of C++ On the development of C++

  • 1998 ISO C++ Standard officially adopted. 776 p.

1998 ISO C++ Standard officially adopted. 776 p. RTTI, namespaces, RTTI, namespaces, export export, , bool bool, new cast syntax, many template , new cast syntax, many template extensions, exception specifications, etc., extensions, exception specifications, etc., std::string std::string, , STL STL

1979 => B.Stroustrup: Adding Classes to C. in Software Practice and Experience, Feb, 1983, pp. 139-161.

  • 2003 ISO standard revision (bug fix release for C++98)

2003 ISO standard revision (bug fix release for C++98)

  • 2003

2003 Library Library TR1: likely components, TR1: likely components, hash hash map, regex, smart pointers.. map, regex, smart pointers..

  • 2006

2006 Performance Performance TR: A TR: A report on C++ performance issues

report on C++ performance issues

  • 2009: Selected “C++0x” features became commonly available

2009: Selected “C++0x” features became commonly available

  • 2011 ISO Standard ("C++0x" => "C++11/14"). 1353 p.

2011 ISO Standard ("C++0x" => "C++11/14"). 1353 p. auto auto, , static_assert static_assert, , constexpr constexpr, , uniform initialization uniform initialization, , move semantic, move semantic, auto auto, , static_assert static_assert, , constexpr constexpr, , uniform initialization uniform initialization, , move semantic, move semantic, lambda expressions lambda expressions, , threads, futures threads, futures, , locks locks, spec. of "machine model", , spec. of "machine model", template aliases, variadic templates, template aliases, variadic templates, extern extern ("do not instantiate here ("do not instantiate here")

")

  • no "

no "concepts concepts" for generics (yet); removed " for generics (yet); removed export export, , auto_ptr auto_ptr, and old , and old version of exception specifications (that had proved to be bad ideas) version of exception specifications (that had proved to be bad ideas)

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 2

A (simplified) family tree of C++ (Stroustup, 2014) A (simplified) family tree of C++ (Stroustup, 2014)

modelling experience with Simula (PhD thesis) => how to efficiently utilize .. other influences: Clu, Algol68, Ada: exceptions, generics,

  • verloading..

how to efficiently utilize classes and inheritance

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 3

On C++ type safety (refreshment) On C++ type safety (refreshment)

C++ is C++ is not not guaranteed to be statically or dynamically type safe guaranteed to be statically or dynamically type safe

  • "a programming language designed for general and performance

"a programming language designed for general and performance critical systems programming with the ability to manipulate critical systems programming with the ability to manipulate hardware cannot be type safe" [Stroustrup] hardware cannot be type safe" [Stroustrup] hardware cannot be type safe" [Stroustrup] hardware cannot be type safe" [Stroustrup]

  • the goal of preserved

the goal of preserved C compatibility compatibility assures such "unsafety", t assures such "unsafety", too

  • Some problems (mostly features inherited from C)

Some problems (mostly features inherited from C)

  • untagged unions (binary data reinterpreted as the current variant)

untagged unions (binary data reinterpreted as the current variant)

  • explicit (and some implicit) unsafe type conversions (casts)

explicit (and some implicit) unsafe type conversions (casts)

  • pointers and arrays without (guaranteed) checks

pointers and arrays without (guaranteed) checks

  • pointers and arrays without (guaranteed) checks

pointers and arrays without (guaranteed) checks

  • ability to deallocate a free store (heap) object while holding on to its

ability to deallocate a free store (heap) object while holding on to its "dangling" pointer (allowing post "dangling" pointer (allowing post-

  • allocation access)

allocation access)

  • deallocating an object not allocated, double deallocations..

deallocating an object not allocated, double deallocations..

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 4

slide-2
SLIDE 2
  • C++ is used in many key areas of the software industry

C++ is used in many key areas of the software industry

  • computer games and entertainment industry

computer games and entertainment industry

  • virtual machines and translator tools (compilers)

virtual machines and translator tools (compilers) audio/video processing audio/video processing

C++ application areas C++ application areas

  • audio/video processing

audio/video processing

  • computer device drivers

computer device drivers

  • control systems

control systems

  • telecommunications systems

telecommunications systems

  • embedded software systems

embedded software systems

  • simulation systems

simulation systems simulation systems simulation systems

  • medical imaging

medical imaging

  • Its implementation and runtime systems make it suitable to its

Its implementation and runtime systems make it suitable to its application areas application areas

  • C++ has many technicalities, subtleties, and features

C++ has many technicalities, subtleties, and features

2.2.2017 2.2.2017 5 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Challenges of C++ (modified from Stroustrup) Challenges of C++ (modified from Stroustrup)

  • preventing potential misuses of manual resource handling (mainly,

preventing potential misuses of manual resource handling (mainly, delete delete) designing sound class hierarchies, and using obscure design designing sound class hierarchies, and using obscure design

  • designing sound class hierarchies, and using obscure design

designing sound class hierarchies, and using obscure design patterns such as the patterns such as the Visitor Visitor pattern pattern

  • difficulty of generic programming and templates ("template meta

difficulty of generic programming and templates ("template meta-

  • programming")

programming")

  • combining object

combining object-

  • oriented and generic programming
  • riented and generic programming
  • making exceptions suitable for hard

making exceptions suitable for hard-

  • real

real-

  • time: eliminating

time: eliminating

  • making exceptions suitable for hard

making exceptions suitable for hard-

  • real

real-

  • time: eliminating

time: eliminating

  • verheads from code unrelated to error handling (?)
  • verheads from code unrelated to error handling (?)
  • providing higher

providing higher-

  • level concurrency models as libraries (?)

level concurrency models as libraries (?)

  • coming

coming: type case, new forms of asserts for prog : type case, new forms of asserts for prog-

  • by

by-

  • contract

contract

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 6

New syntax and semantics (2011) New syntax and semantics (2011)

  • new uniform

new uniform initialization syntax initialization syntax

  • ld C++ provided many
  • ld C++ provided many different

different ways to initialize objects ways to initialize objects

  • now, one new way

now, one new way { . . . } { . . . } works similarly for (most) situations works similarly for (most) situations

  • new keywords:

new keywords: static_assert static_assert, , constexpr constexpr, noexcept noexcept

  • new

new contextual contextual keywords: keywords: final override final override (ids but in special context) (ids but in special context)

  • meaning changed

meaning changed (extended extended): : auto auto, , delete delete, default default

  • move semantics

move semantics: can efficiently can efficiently move over move over a whole (internal) data a whole (internal) data representation representation

  • lambda

lambda expressions expressions, with various kinds of , with various kinds of captured variables captured variables

  • template aliases

template aliases, , extern extern & & variadic templates variadic templates

  • support for using

support for using user user-defined defined "literals literals".. "..

  • threads

threads, , futures futures, , locks locks, specification of " , specification of "machine machine model model" (memory) " (memory)

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 7

C++11 features to prefer C++11 features to prefer

  • auto

auto (type derivation for variables, and range loops) (type derivation for variables, and range loops)

  • nullptr

nullptr (replacing 0 or NULL; for smart pointers, too) (replacing 0 or NULL; for smart pointers, too)

  • range

range-

  • based

based-

  • for

for-

  • loops (

loops ( for (int & e : container) . . . for (int & e : container) . . . ) )

  • range

range-

  • based

based-

  • for

for-

  • loops (

loops ( for (int & e : container) . . . for (int & e : container) . . . ) )

  • "override
  • verride" and "

" and "final final" for " for virtual virtual functions overrides ( ~ Java/C#) functions overrides ( ~ Java/C#)

  • scoped

scoped enums (qualified by enum name, no integral conversions) enums (qualified by enum name, no integral conversions)

  • smart pointers

smart pointers (resource handling, and exception safety) (resource handling, and exception safety)

  • lambdas

lambdas (can be used for, e.g., (can be used for, e.g., STL STL algorithms algorithms and and concurrency concurrency) )

  • non

non-member member begin () and end () begin () and end () (work with any type) (work with any type)

  • non

non-member member begin () and end () begin () and end () (work with any type) (work with any type)

  • static_assert

static_assert (compile (compile-

  • time check) and

time check) and type traits type traits (at compile (at compile-

  • time, to query or modify the properties of types)

time, to query or modify the properties of types)

  • move

move semantics semantics (efficiently construct/copy a value) (efficiently construct/copy a value)

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 8

slide-3
SLIDE 3

New New noexcept noexcept specification specification

  • A noexcept

noexcept specification enables a programmer to inform the specification enables a programmer to inform the compiler that a function compiler that a function should should not not throw throw exceptions exceptions

  • an improved (with less overhead) version of the old C++03

an improved (with less overhead) version of the old C++03 an improved (with less overhead) version of the old C++03 an improved (with less overhead) version of the old C++03 "throw() throw()" specification which is deprecated in C++11 " specification which is deprecated in C++11

  • The compiler can use this information to enable certain optimizations

The compiler can use this information to enable certain optimizations

  • n such non
  • n such non-throwing functions

throwing functions

  • for example, containers such as

for example, containers such as std::vector std::vector will move their will move their elements if the elements' elements if the elements' move move constructor is constructor is noexcept noexcept, and copy , and copy

  • therwise (
  • therwise (- needed to support exception safety)

needed to support exception safety)

  • therwise (
  • therwise (- needed to support exception safety)

needed to support exception safety)

  • If a function marked

If a function marked noexcept noexcept allows an uncaught exception to allows an uncaught exception to escape at runtime, => escape at runtime, => fatal error fatal error, and , and std::terminate std::terminate is called is called immediately immediately

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 9

Motivation: how to return data efficiently? Motivation: how to return data efficiently?

New C++11 solution: use New C++11 solution: use move semantics move semantics to "steal the rep" to "steal the rep"

  • To support the convential ("natural") algorithm and notations:

To support the convential ("natural") algorithm and notations:

Vector operator + (Vector const& a, Vector const& b) { Vector operator + (Vector const& a, Vector const& b) { Vector r; Vector r; // // for each for each i, copy , copy a a [ [i] ] + + b b [ [i] ] into into r r [ [i] ] return r; return r; } . . . } . . . Vector res = a + b; Vector res = a + b; // // clear and natural clear and natural

a temporary object is created here (recognized by the compiler)

Vector res = a + b; Vector res = a + b; // // clear and natural clear and natural

  • To provide an efficient implementation, the

To provide an efficient implementation, the Vector Vector type needs type needs to provide a new special to provide a new special move constructor move constructor

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 10 10

Copying state vs. moving Copying state vs. moving state state

  • Moving

Moving is a is a key new C++ key new C++11 idea 11 idea

  • usually an optimization

usually an optimization of copying

  • f copying
  • C++ has always supported copying object state:

++ has always supported copying object state: copy constructors, copy assignment operators copy constructors, copy assignment operators

  • copy constructors, copy assignment operators

copy constructors, copy assignment operators

  • C++

C++11 now adds 11 now adds support for requests to support for requests to move object state move object state: : Vector w1 Vector w1; . . . ; . . . // // STL STL-style vector style vector Vector w2 (w1); Vector w2 (w1); // // (1) (1) copy copy w1 w1’s state to ’s state to w2 w2 Vector w3 Vector w3; . . . ; . . . Vector w4 (std::move (w3)); Vector w4 (std::move (w3)); // (2) // (2) move move w3 w3’s state to ’s state to w4 w4 Vector w4 (std::move (w3)); Vector w4 (std::move (w3)); // (2) // (2) move move w3 w3’s state to ’s state to w4 w4 Note Note: Above, the : Above, the w3 w3 continues to exist in a valid state after creation continues to exist in a valid state after creation of

  • f

w4 w4 (generally: (generally: valid valid but but indeterminate indeterminate state!); here state!); here valid valid means that means that the object can be destructed (by the compiler) the object can be destructed (by the compiler)

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 11 11

C++11: C++11: move move constructors constructors

  • Often, the constructor gets a temporary that

Often, the constructor gets a temporary that can can lose its value lose its value

  • Implement the transfer of internal representation

Implement the transfer of internal representation

class Vector { . . . class Vector { . . . // // illustrative pseudocode, only illustrative pseudocode, only class Vector { . . . class Vector { . . . // // illustrative pseudocode, only illustrative pseudocode, only Vector Vector ( (Vector&& a Vector&& a) ) noexcept noexcept { // { // no no const const here here rep = a.rep; rep = a.rep; // // *this this gets gets ( (steals steals) ) a’s elements ’s elements a.rep = nullptr; a.rep = nullptr; // a // a becomes empty becomes empty } } . . . . . . private: private: Rep Rep * rep; rep; // // some hypothetical representation some hypothetical representation Rep Rep Rep Rep * rep; rep; // // some hypothetical representation some hypothetical representation Rep Rep }; }; . . . . . . Vector res = a + b; Vector res = a + b; // // now, the temporary result is now, the temporary result is // // efficiently efficiently passed on passed on

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 12 12

slide-4
SLIDE 4

lvalues lvalues vs.

  • vs. rvalues

rvalues (simplified (simplified)

  • An

An lvalue lvalue is an expression that refers to a is an expression that refers to a memory location memory location, and, e.g., , and, e.g., allows us to take the address (&) of that location allows us to take the address (&) of that location

  • Essentially, an

Essentially, an rvalue rvalue is any expression that is not an is any expression that is not an lvalue lvalue (often, a (often, a

  • Essentially, an

Essentially, an rvalue rvalue is any expression that is not an is any expression that is not an lvalue lvalue (often, a (often, a temporary temporary result); examples of result); examples of lvalues lvalues and and rvalues rvalues: : int int i = 42; = 42; i = 43; = 43; // // ok,

  • k, i

i is an is an lvalue lvalue int int * p = & p = &i; ; // // ok,

  • k, i

i is an is an lvalue lvalue int& foo (); foo () int& foo (); foo () = 42; = 42; // // ok

  • k,

, foo () foo () is an is an lvalue lvalue int int * p1 = p1 = &foo (); &foo (); // // ok

  • k,

, foo () foo () is an is an lvalue lvalue int int * p1 = p1 = &foo (); &foo (); // // ok

  • k,

, foo () foo () is an is an lvalue lvalue int int foobar foobar (); int j = (); int j = foobar foobar (); (); // // ok,

  • k, foobar ()

foobar () is an rvalue is an rvalue int int * p2 = p2 = &foobar () &foobar (); ; // // error error: : address of an address of an rvalue rvalue

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 13 13

Rvalue Rvalue reference reference (&& &&) type ) type

  • If

If X X is any type, then is any type, then X&& X&& is called an is called an rvalue rvalue reference reference to X to X

  • implemented

implemented much like the ordinary reference much like the ordinary reference X& & (pointers) (pointers)

  • the

the ordinary reference

  • rdinary reference X&

X& is now called an is now called an lvalue lvalue reference reference

  • the

the ordinary reference

  • rdinary reference X&

X& is now called an is now called an lvalue lvalue reference reference

  • Rvalue reference parameters allow

Rvalue reference parameters allow a new kind of function a new kind of function

  • verloading resolution
  • verloading resolution

void fn (X&& x void fn (X&& x); ); // // rvalue rvalue reference overload reference overload . . . . . . fn (X ()); fn (X ()); // // an rvalue an rvalue: calls calls fn (X&&) fn (X&&) fn (X ()); fn (X ()); // // an rvalue an rvalue: calls calls fn (X&&) fn (X&&)

  • This

This kind of kind of overload is

  • verload is usually

usually used only for constructors used only for constructors and and assignment operators assignment operators, to achieve , to achieve move semantics move semantics

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 14 14

Summary: handling Summary: handling results results efficiently efficiently

  • Temporary objects are prime candidates for moving:

Temporary objects are prime candidates for moving: Vector Vector createVector createVector (); (); // // produce a produce a Vector Vector (func prototype! func prototype!) Vector Vector createVector createVector (); (); // // produce a produce a Vector Vector (func prototype! func prototype!) Vector v Vector v; ; . . . . . . v = createVector (); v = createVector (); // // in in C++98, C++98, copies copies value to value to v

  • C++

C++11 now (often) 11 now (often) turns such copy operations into turns such copy operations into move move requests: requests: Vector v; Vector v; . . . . . . v v = createVector (); = createVector (); // // implicit move request in implicit move request in C++11 C++11

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 15 15

A (very simplified) STL A (very simplified) STL-style style container container Seq Seq

class Seq { class Seq { // // a hypothetical container for strings a hypothetical container for strings public: public: Seq (); Seq (); // // default ctor default ctor: make empty make empty Seq Seq explicit explicit Seq (int n); Seq (int n); // // ctor ctor: initialize to initialize to n elements elements

Note

Seq ( Seq (std::initializer_list <string> std::initializer_list <string>) ; // ) ; // ctor ctor: initialize with a list initialize with a list { . . . } { . . . } ~Seq (); ~Seq (); // // dtor dtor: deallocate elements deallocate elements int size () const; int size () const; // // number of elements number of elements String& operator [] (int i); String& operator [] (int i); // // access the i'th element access the i'th element void pushBack (String const& x); // void pushBack (String const& x); // add a new item at the end add a new item at the end String String * begin (); begin (); // // first element first element String String * end (); end (); . . . . . . // // one

  • ne-beyond

beyond-last element last element String String * end (); end (); . . . . . . // // one

  • ne-beyond

beyond-last element last element private: private: int sz; int sz; // // number of elements number of elements String String * elem; elem; // // pointer to pointer to sz sz elements elements }; };

Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 16 16 2.2.2017 2.2.2017

What is missing? What is missing?

slide-5
SLIDE 5

Defining Defining coping coping and and moving moving within a class within a class

class Seq { class Seq { public: public: public: public: // . . . // . . . Seq (Seq Seq (Seq const const&); &); // // copy constructor copy constructor Seq (Seq &&) Seq (Seq &&) noexcept noexcept; ; // // move move constructor constructor Seq& operator = (Seq Seq& operator = (Seq const const&); &); // // copy assignment copy assignment Seq& operator = (Seq &&) Seq& operator = (Seq &&) noexcept noexcept; ; // // move move assignment assignment // // . . . . . . // // . . . . . . }; };

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 17 17

Writing Writing move move member member functions functions

  • Write your move overloads

rite your move overloads in such a way that they cannot in such a way that they cannot throw exceptions throw exceptions

  • that

that is is often both natural and trivial

  • ften both natural and trivial, because move

, because move semantics typically do no more semantics typically do no more than manipulate pointers than manipulate pointers and resource handles between two objects and resource handles between two objects

  • If

If you succeed in you succeed in not throwing not throwing any exceptions any exceptions from your from your

  • verloads,
  • verloads, then

then

  • make sure to advertise that fact using the new

make sure to advertise that fact using the new noexcept noexcept keyword (see the previous slide) keyword (see the previous slide)

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 18 18

Move constructor and move assignment Move constructor and move assignment

Seq::Seq (Seq Seq::Seq (Seq&& && v) noexcept v) noexcept // // no no const const here here : sz { v.sz }, elem { v.elem } { : sz { v.sz }, elem { v.elem } { // // grab grab v’s elements ’s elements v.elem = nullptr; v.sz = 0; v.elem = nullptr; v.sz = 0; // // and make and make v empty empty v.elem = nullptr; v.sz = 0; v.elem = nullptr; v.sz = 0; // // and make and make v empty empty } Seq& Seq::operator = (Seq Seq& Seq::operator = (Seq&& && v) noexcept { // v) noexcept { // no no const const here here delete elem; delete elem; // // dtors can't dtors can't throw throw elem = v.elem; elem = v.elem; sz = v.sz; sz = v.sz; // // grab grab v’s elements ’s elements v.elem = nullptr; v.sz = 0; v.elem = nullptr; v.sz = 0; // // make make v empty empty return return this; this; return return *this; this; }

  • Now, (depending on the context) the compiler can "automatically"

Now, (depending on the context) the compiler can "automatically" use appropriately either copy or move operations use appropriately either copy or move operations

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 19 19

A move A move request request by by std std::move ::move

  • In C++11, there is an standard library function called

In C++11, there is an standard library function called std::move std::move that that can be can be used to suggest/enforce a used to suggest/enforce a move (e.g., inside an implementation) move (e.g., inside an implementation)

  • It

It is a function that is a function that turns its given turns its given argument into an argument into an rvalue rvalue reference reference without doing anything else without doing anything else without doing anything else without doing anything else

  • Essentially

Essentially, for a , for a type type T, it’s , it’s std::move std::move function function is defined is defined T&& T&& move move (T& a (T& a) ) noexcept { // noexcept { // from template from template std::move std::move return return static_cast static_cast <T&&> <T&&> (a) (a); ; } } . . . . . . . . . . . . std::string std::string s = "Hello"; = "Hello"; . . . . . . std::vector <std::string> std::vector <std::string> v; ; . . . . . . v.push_back ( .push_back (std::move (s) std::move (s)); ); // // the contents of the contents of s is is moved moved

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 20 20

slide-6
SLIDE 6

Some STL details/technicalities: when to Some STL details/technicalities: when to move move

  • Depending on circumstances, C

Depending on circumstances, C++ ++11 (generally 11 (generally) turns copy turns copy

  • perations on
  • perations on rvalues

rvalues into into move move operations, but

  • perations, but not always

not always

  • some
  • me operations (e.g.,
  • perations (e.g., std::vector::

std::vector::push_back push_back) offer the ) offer the strong exception strong exception-safety guarantee, so moving can replace safety guarantee, so moving can replace strong exception strong exception-safety guarantee, so moving can replace safety guarantee, so moving can replace copying copying only

  • nly if the move operations

if the move operations are known are known not to throw not to throw (e.g., by declaring them (e.g., by declaring them noexcept noexcept)

  • Moving a whole container (generally)

Moving a whole container (generally) requires that the container’s requires that the container’s allocator be movable, which need allocator be movable, which need not (necessarily) be the case not (necessarily) be the case

'

  • If the allocator is not movable, the elements of the container must

If the allocator is not movable, the elements of the container must

  • If the allocator is not movable, the elements of the container must

If the allocator is not movable, the elements of the container must be individually copied, unless the element type’s move constructor be individually copied, unless the element type’s move constructor is known not to throw, in which case they may is known not to throw, in which case they may be moved be moved

  • a utility

a utility std::move_if_noexcept std::move_if_noexcept gives an gives an rvalue reference rvalue reference for a for a noexcept noexcept move constructor, otherwise an move constructor, otherwise an lvalue reference lvalue reference

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 21 21

C++11 provides C++11 provides move move constructors constructors

  • The standard

The standard-

  • library containers now support

library containers now support move move constructors and constructors and move move assignments, assignments, for for example example std::vector std::vector std::vector std::vector std::list std::list std::forward_list std::forward_list (singly (singly-

  • linked list)

linked list) std::map std::map std::unordered_map std::unordered_map (hash table) (hash table) std::set std::set std::string . . . std::string . . .

  • Of course, recommended for

Of course, recommended for any new custom any new custom data structures, too data structures, too

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 22 22

Sometimes, moving allowed Sometimes, moving allowed – but but not not copying copying

  • Generally, most

Generally, most standard types in C++11 are standard types in C++11 are move move-enabled enabled

  • they

they support move requests support move requests e.g., STL containers e.g., STL containers

  • e.g., STL containers

e.g., STL containers

  • But some types are actually

But some types are actually move move-only

  • nly:

: copying is copying is prohibited, but prohibited, but moving moving is allowed is allowed

  • ften kind of abstractions that are (or represent) somehow
  • ften kind of abstractions that are (or represent) somehow

"unique" values and don't have a copy operation that would "unique" values and don't have a copy operation that would make any sense make any sense make any sense make any sense

  • e.g

e.g., ., stream stream objects,

  • bjects, std::thread

std::thread objects,

  • bjects, std::

std::unique_ptr unique_ptr, , etc. etc.

  • nly allowed overloads are provided
  • nly allowed overloads are provided

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 23 23

Lambda Lambda expressions expressions

Using lambdas with of STL libraries and types Using lambdas with of STL libraries and types

  • for

for-loop vs . loop vs . for_each for_each () + lambda () + lambda

  • can give identical performance on several compilers

can give identical performance on several compilers

  • can give identical performance on several compilers

can give identical performance on several compilers

std::vector <int> v = { 35, 92, 68 }; // std::vector <int> v = { 35, 92, 68 }; // init with init with new syntax new syntax sum sum = 0; = 0; 1.

  • 1. for (std::vector <int>::size_type i = 0; i < v.size (); ++i)

for (std::vector <int>::size_type i = 0; i < v.size (); ++i) sum += v [i]; sum += v [i];

here, explicitly captured by reference

  • ld style C++ container-for-loop;
  • r could use iterators

2.

  • 2. //

// using STL algorithm + lambda using STL algorithm + lambda for_each (v.begin (), v.end (), for_each (v.begin (), v.end (), [&sum](int x) { sum += x; } [&sum](int x) { sum += x; } ); ); 3.

  • 3. for (auto x : v) sum += x;

for (auto x : v) sum += x; // // range range for for; type deduced from type deduced from v

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 24 24

slide-7
SLIDE 7

Resource management (revisited) Resource management (revisited)

  • Remember the RAII:

Remember the RAII: resource acquisition is initialization resource acquisition is initialization

  • Many classes include resource management as part of their

Many classes include resource management as part of their fundamental semantics fundamental semantics

  • e.g.,

e.g., std::vector std::vector, , std::ostream std::ostream, , std::thread std::thread.. ..

  • e.g.,

e.g., std::vector std::vector, , std::ostream std::ostream, , std::thread std::thread.. ..

  • "Smart pointers

Smart pointers" can be used to address many of the remaining " can be used to address many of the remaining problems of destruction and leaks problems of destruction and leaks

  • std::unique_ptr

std::unique_ptr for (unique) ownership for (unique) ownership

  • practically zero cost (in time and space)

practically zero cost (in time and space)

  • std::shared_ptr

std::shared_ptr for shared ownership for shared ownership

assignment assignment transfers transfers

  • wnership
  • wnership
  • std::shared_ptr

std::shared_ptr for shared ownership for shared ownership

  • maintains

maintains use counts use counts (some options provided..) (some options provided..)

  • but still using

but still using any any pointers may result in unwanted sharing pointers may result in unwanted sharing – even in a single even in a single-threaded program threaded program

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki 25 25

Issues in architecture Issues in architecture of C++ programs

  • f C++ programs

The basic principles of The basic principles of object

  • bject-
  • oriented programming
  • riented programming
  • programming to an interface

programming to an interface, class hierarchies, frameworks.. , class hierarchies, frameworks..

  • design patterns

design patterns: problem solutions (inheritance : problem solutions (inheritance & composition) composition)

  • sample patterns in C++:

sample patterns in C++: Template Method Template Method, , Singleton, Bridge Singleton, Bridge, , Factory Factory Large Large-

  • scale

scale C++ programming (game engines, virtual machines,..) C++ programming (game engines, virtual machines,..)

  • what if software is "big" (> 10000) or "huge" (>100000)

what if software is "big" (> 10000) or "huge" (>100000)

  • we should take modularization very seriously!

we should take modularization very seriously! How How to physically organize a to physically organize a large large C++ program into ++ program into files files

  • modularity

modularity, header files, and , header files, and breaking unwanted dependencies breaking unwanted dependencies

  • logical vs. physical dependencies between program

logical vs. physical dependencies between program units units

  • proper use of

proper use of namespaces namespaces

26 26 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

On modularity On modularity

  • Important

Important goals in software construction are goals in software construction are maintainability maintainability and and reusability reusability

  • both are supported by

both are supported by modularity modularity: minimizing the dependencies : minimizing the dependencies between program units or between program units or subsystems ( subsystems (components/engines/layers) components/engines/layers)

  • Background and ideas:

Background and ideas:

  • interfaces

interfaces (services) are often more stable than (services) are often more stable than implementations implementations

  • try

try to make client code as independent as possible from changes in to make client code as independent as possible from changes in implementations implementations (by providing (by providing representation representation independence independence)

  • C++ classes (as

++ classes (as abstract data types abstract data types) support a kind of logical ) support a kind of logical modularity (with its modularity (with its public public vs.

  • vs. private

private parts) parts) modularity (with its modularity (with its public public vs.

  • vs. private

private parts) parts)

  • but

but private private members still come along as a part of the class members still come along as a part of the class definition, definition, and and often

  • ften create

create unnecessary unnecessary dependencies dependencies

  • in

in C++, try to pass C++, try to pass minimal minimal information information to to other

  • ther program units

program units - preferably include preferably include no headers no headers at at all (replace by all (replace by name stubs name stubs)

27 27 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Headers and physical dependencies Headers and physical dependencies

  • I

In n C++, the actual C++, the actual physical dependencies physical dependencies between program units are between program units are manifasted in manifasted in header header files files (since they are shared around) (since they are shared around)

  • a

a class definition and its implementation class definition and its implementation ( (private private data data members) members) are strongly connected, and are strongly connected, and changes in changes in the the private private part part cause cause are strongly connected, and are strongly connected, and changes in changes in the the private private part part cause cause recompilation recompilation of the client's

  • f the client's code (since sizes may have changed)

code (since sizes may have changed)

  • also,

also, concrete object creation builds strong concrete object creation builds strong dependencies dependencies

  • again, code

again, code that that creates creates objects compiles only if the compiler

  • bjects compiles only if the compiler

has access to the has access to the definitions definitions and and the sizes of the types the sizes of the types of the

  • f the

data data members (even if they are members (even if they are private private) )

  • The

The Bridge Bridge design pattern can be used to completely separate design pattern can be used to completely separate interface hierarchies from implementation structures interface hierarchies from implementation structures

  • Using

Using Factory Factory patterns can break patterns can break dependencies and dependencies and decouple decouple program units program units (discussed with design patterns) (discussed with design patterns)

28 28 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

slide-8
SLIDE 8

Problem: unnecessary header dependencies Problem: unnecessary header dependencies

// // file file: : "data.h data.h" class class Data Data { { . . . . . }; . }; // // some data definition some data definition

  • - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - - - - - - - -

// // file file: : "client.h client.h" " - a header file that needs a header file that needs Data Data // // file file: : "client.h client.h" " - a header file that needs a header file that needs Data Data #include "data.h" . . . #include "data.h" . . . // // get get the the Data Data class definition class definition class Client { class Client { // // compiles compiles OK OK, but , but bad style bad style Data query () const; Data query () const; . . . . . . private: private: Data Data * ptrData_; ptrData_;

29 29

* }; };

  • Now, any changes

Now, any changes to to Data Data propagate to propagate to Client Client-related source code related source code

  • The

he physical physical dependence (file include) dependence (file include) may create maintenance may create maintenance problems problems - or,

  • r, sometimes,

sometimes, force force long long-lasting recompilations lasting recompilations

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Required class Required class information? information?

What information What information is actually is actually required from the class required from the class X in order to in order to compile client code? For example compile client code? For example: X obj; // X obj; // here compiler here compiler needs to know instance needs to know instance size size . . . . . . new X; // new X; // to to allocate space for the object allocate space for the object . . . . . . new X; // new X; // to to allocate space for the object allocate space for the object However, this information is However, this information is not required not required for: for: (1) (1) members members with pointers or references, e.g., with pointers or references, e.g., X X *, , X& X&, or , or X&& X&& (2) (2) function function declarations declarations even with even with value parameters or value parameters or results results X X getX () getX () or

  • r void print (X par)

void print (X par) need need only

  • nly name declaration

name declaration of

  • f X

30 30

  • the

the caller caller of the operations needs the definitions to determine the

  • f the operations needs the definitions to determine the

required sizes required sizes -

  • to

to actually actually to create/pass values (within a . to create/pass values (within a .cpp cpp file) file)

  • thus,

thus, often header

  • ften header files don't

files don't actually require full class definitions in actually require full class definitions in

  • rder to
  • rder to define

define their own services their own services and interfaces and interfaces

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Breaking unwanted dependencies Breaking unwanted dependencies

// // file file "client.h client.h" - better modified header file better modified header file class Data class Data; ; // // forward forward declaration declaration only

  • nly (name stub

name stub) class Client { class Client { public: public: public: public: Data Data query () const; . . query () const; . . . // // OK OK: no : no implementation needed implementation needed (yet yet) private: private: Data Data * pData_; . . . pData_; . . . // // OK OK: no : no implementation needed implementation needed (yet yet) }; };

  • Only source

nly source code that actually creates objects needs to include code that actually creates objects needs to include

31 31

  • Only source

nly source code that actually creates objects needs to include code that actually creates objects needs to include appropriate header appropriate header files files

  • e.g

.g., " ., "client.cpp client.cpp" " usually needs usually needs to include " to include "data.h data.h" "

  • but

but no problem no problem since since it it is an is an isolated isolated program program unit unit

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Problems with templates and headers Problems with templates and headers

  • N

Not

  • t all

all classes classes can be forwarded with names only can be forwarded with names only (with a name stub) (with a name stub)

  • std::string

std::string is is a a typedef typedef of a template instance

  • f a template instance (not named classs)

(not named classs)

  • T

The he standard library provides standard library provides a special a special header header <iosfwd <iosfwd>, >, with with

  • minimal

minimal declarations for stream templates and their standard declarations for stream templates and their standard typedef typedefs, such as s, such as std:: std::ostream =>

  • stream => optimize compilation process
  • ptimize compilation process
  • unfortunately, no such forward header file exists for

unfortunately, no such forward header file exists for std::string std::string

  • similar

similar practice practice recommended recommended for for user user-

  • defined headers:

defined headers: myfwd.h myfwd.h

  • collect the

collect the minimal name info minimal name info (name stubs) into (name stubs) into a a header header Note that C Note that C++ implementations sometimes ++ implementations sometimes #include #include extra header files extra header files

32 32

  • Note that C

Note that C++ implementations sometimes ++ implementations sometimes #include #include extra header files extra header files along system along system headers (for internal purposes), headers (for internal purposes), making code nonportable making code nonportable

  • in another

in another platform, such "missing" platform, such "missing" headers headers may break may break compilation compilation

  • minimize dependencies on nested

minimize dependencies on nested #include includes s by always including by always including system headers as the last ones system headers as the last ones

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

slide-9
SLIDE 9
  • Also

lso known as the known as the Handle Handle-Body Body idiom (or "compilation firewall", or idiom (or "compilation firewall", or "Cheshire Cat" technique: "leaving only the smile behind") "Cheshire Cat" technique: "leaving only the smile behind")

  • The whole class

he whole class definition, with its definition, with its private private and and protected protected parts, is parts, is unnecessarily unnecessarily carried along when compiling the carried along when compiling the client's code client's code

Idiom: Pimpl ( Idiom: Pimpl (Pointer to

  • inter to impl

impl.) .)

unnecessarily unnecessarily carried along when compiling the carried along when compiling the client's code client's code

  • this

this physical physical coupling coupling hinders maintenance hinders maintenance

  • To completely separate abstraction
  • completely separate abstraction and

and its implementation its implementation, , replace replace an object/data by a pointer to it (and omit all data definitions) an object/data by a pointer to it (and omit all data definitions) class Abstraction class Abstraction { { // // the the handle handle part part . . . . .

the pointer size doesn't change

33 33

private private: : // // the the private private part is replaced part is replaced struct Impl struct Impl * body_; body_; // // by a pointer to the by a pointer to the body body }; }; // // the the struct Impl struct Impl is is defined defined and and hidden hidden in a .cpp file in a .cpp file

2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

the pointer size doesn't change

C++ global C++ global name space name space

  • Namespace

amespace defines a defines a scope, scope, and anything that can be globally defined and anything that can be globally defined can also be defined in a can also be defined in a namespace namespace

  • A

All ll declarations that are not explicitly placed in a named namespace declarations that are not explicitly placed in a named namespace

  • A

All ll declarations that are not explicitly placed in a named namespace declarations that are not explicitly placed in a named namespace become part of become part of the one the one global global namespace namespace (a bad thing!) (a bad thing!) Rule Rule

  • Don't

Don't ever corrupt the global namespace with user ever corrupt the global namespace with user-

  • defined names

defined names ( (but but a limited set of top a limited set of top-

  • level

level namespace names namespace names) ) Accessing the global namespace Accessing the global namespace:

Historically, String classes.

Accessing the global namespace Accessing the global namespace:

  • inside a namespace, in definitions of its members, you can refer to a

inside a namespace, in definitions of its members, you can refer to a name in the name in the outermost global

  • utermost global namespace using the scope operator

namespace using the scope operator :: :: ::GlobalName ::GlobalName // // refer refer to to a file a file-

  • scope name,

scope name, from anywhere from anywhere

34 34 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Namespaces Namespaces

  • A namespace definition is

namespace definition is open

  • pen:

:

  • can

can add members to the existing namespace by writing later a new add members to the existing namespace by writing later a new namespace section namespace section { . . . } { . . . } with with the the same same name name: : means extension means extension

  • for example, assuming

for example, assuming an earlier an earlier definition of definition of Company Company, you can , you can

  • for example, assuming

for example, assuming an earlier an earlier definition of definition of Company Company, you can , you can add an additional member to this namespace add an additional member to this namespace: : namespace Company { namespace Company { // // extending an existing extending an existing namespace namespace class class Volunteer Volunteer { . . . }; // { . . . }; // adds adds a new member a new member } }

  • Now
  • w,

, we we can distribute a namespace into multiple header files, each can distribute a namespace into multiple header files, each defining some defining some closely related closely related set of specific services set of specific services defining some defining some closely related closely related set of specific services set of specific services

  • e.g., needed for defining the standard namespace

e.g., needed for defining the standard namespace std std (lately (lately, the , the use of just a use of just a single single namespace namespace std std has been criticized has been criticized)

  • No

No keywords to keywords to specify the specify the accessibility of individual accessibility of individual members members

  • but we

but we can can hide them inside an hide them inside an unnamed namespace unnamed namespace; see later ; see later

35 35 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Namespaces (cont.) Namespaces (cont.)

  • A

A namespace namespace may may contain only the contain only the declaration declaration of a

  • f a member (in a .

member (in a .h) )

  • The

The corresponding corresponding definitions definitions can be provided can be provided outside

  • utside of the
  • f the namespace

namespace (in the . (in the .cpp cpp file); must use file); must use Namespace Namespace:: ::Name Name to specify to specify the member the member (in the . (in the .cpp cpp file); must use file); must use Namespace Namespace:: ::Name Name to specify to specify the member the member namespace namespace Company Company { // // .h .h void void foo (); foo (); // // declare declare a function a function class class Employee Employee { . . . }; { . . . }; // // plus plus: declare operations declare operations } // . . . } // . . . void Company::foo () void Company::foo () { . . . } { . . . } // // .cpp cpp: : definition definition of operation

  • f operation

void Company::foo () void Company::foo () { . . . } { . . . } // // .cpp cpp: : definition definition of operation

  • f operation

void Company::Employee::op () void Company::Employee::op () { . . . } { . . . } // // parameters must match parameters must match

  • This

This strategy makes it completely explicit in which namespace the name strategy makes it completely explicit in which namespace the name is is originally defined (and may

  • riginally defined (and may prevent and expose

prevent and expose potential mixups) potential mixups)

36 36 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

slide-10
SLIDE 10

Unnamed namespaces Unnamed namespaces

  • To

To limit the scope and accessibility of a variable, function, or class to a limit the scope and accessibility of a variable, function, or class to a single single file, place it in an file, place it in an unnamed unnamed namespace namespace

  • Replaces C's global (file

eplaces C's global (file-scope) scope) static static declarations declarations ( => ( => internal name) internal name) namespace { namespace { // a hypothetical "< // a hypothetical "<UNNAMED UNNAMED>" >" namespace namespace int value int value_; _; // // private variable private variable (zero by default zero by default) void void SetValue SetValue (int value) (int value) { { // // also also private private value value_= k; _= k; } } } // // if the same file continues, we have .. if the same file continues, we have .. } // // if the same file continues, we have .. if the same file continues, we have .. // // here implicit here implicit: "using "using namespace < namespace <UNNAMED UNNAMED>" >" SetValue SetValue (77); (77); // // compiler sees compiler sees: : <UNNAMED UNNAMED>:: >::SetValue SetValue

  • Members of unnamed namespaces can be used without qualification but

Members of unnamed namespaces can be used without qualification but

  • nly in the same file
  • nly in the same file

37 37 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

using sing declarations declarations

  • Use

Use fully qualified names ( fully qualified names (std std:: ::cout cout), ), or

  • r import often used names

import often used names with with using using declarations declarations using using Company::print; Company::print; // // adds a adds a local local declaration declaration print (); print (); // // means means: : Company:: Company::print () print () print (); print (); // // means means: : Company:: Company::print () print ()

  • Since

Since the the using using declaration declaration adds a declaration to the scope adds a declaration to the scope, it can , it can prevent and reveal prevent and reveal dangerous conflicts (name collisions): dangerous conflicts (name collisions): void goo () { void goo () { int value int value; ; . . . . . . using NamespaceX::value; using NamespaceX::value; // // error error: trying redeclare trying redeclare using NamespaceX::value; using NamespaceX::value; // // error error: trying redeclare trying redeclare using Company::print; using Company::print; // // OK OK: : can declare locally can declare locally print (); print (); // // Company Company::print ::print ::print (); ::print (); // // access access some some ( (odd legacy

  • dd legacy)

) global global print print } }

38 38 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Namespace Namespace aliases aliases

  • We should use

We should use descriptive descriptive and and unambiguous unambiguous names for names for our

  • ur

namespaces namespaces

  • but this may

but this may lead to long and cumbersome lead to long and cumbersome symbols symbols

  • To
  • simplify the use of long names,

simplify the use of long names, we we can introduce one or can introduce one or more more local local aliases: aliases:

namespace CompanyFromSomewhere { namespace CompanyFromSomewhere { . . . . . . } namespace Company = CompanyFromSomewhere; namespace Company = CompanyFromSomewhere; // // alias alias namespace Company = CompanyFromSomewhere; namespace Company = CompanyFromSomewhere; // // alias alias Company::Employee e; Company::Employee e; // // OK: OK: uses alias uses alias

39 39 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

Style rules for namespaces Style rules for namespaces

  • Use namespaces to express logical structure, and d

Use namespaces to express logical structure, and don't

  • n't define

define components outside components outside namespaces namespaces

  • place related

place related classes, interfaces, etc., in a common classes, interfaces, etc., in a common namespace namespace

  • Don't ever

Don't ever use a use a using using directive directive: local declarations may then silently : local declarations may then silently (accidentally) override imported names (accidentally) override imported names

  • tutorials often use

tutorials often use using using directives, but directives, but it's bad style it's bad style

  • Stroustrup

Stroustrup: a transient strategy : a transient strategy (needed only for (needed only for outdated

  • utdated

compilers to make namespaces work) compilers to make namespaces work)

  • A header

A header file may not contain even file may not contain even using using declarations declarations: :

  • use

use fully qualified fully qualified names to make all header files independent of names to make all header files independent of modifications of namespaces (system/own) modifications of namespaces (system/own)

  • Use

Use the the Namespace Namespace:: ::Member Member notation when notation when defining defining (implementing) (implementing) namespace members namespace members (see slide 36) (see slide 36)

40 40 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki

slide-11
SLIDE 11

C++ application C++ application architecture: Summary architecture: Summary

  • Use

se namespaces, and namespaces, and using using declarations declarations (never (never directives directives)

  • Always write

Always write full namespace paths full namespace paths in header files in header files

  • Don't

Don't reveal implementation details in reveal implementation details in header files header files, and include only , and include only those those headers headers that are needed to make that are needed to make your your source to source to compile compile those those headers headers that are needed to make that are needed to make your your source to source to compile compile

  • prefer using

prefer using class class forward forward declarations declarations (name stubs name stubs)

  • supported by writing special name

supported by writing special name-fwd headers (" fwd headers ("myFwd.h myFwd.h") ")

  • Use the

Use the Pimpl Pimpl idiom to separate abstraction and its implementation idiom to separate abstraction and its implementation

  • Hide those

Hide those implementation parts inside an implementation parts inside an unnamed namespace unnamed namespace within within implementation units implementation units (. (.cpp cpp files files) implementation units implementation units (. (.cpp cpp files files)

  • First

First include user include user-defined defined (custom (custom) header ) header files files

  • Use

Use design patterns design patterns to make some aspects (structure or behavior) to make some aspects (structure or behavior)

  • f software separate and thus easily manageable/changeable
  • f software separate and thus easily manageable/changeable
  • remember basic patterns:

remember basic patterns: Singleton, Singleton, Bridge, Factory Bridge, Factory, , Strategy Strategy.. ..

41 41 2.2.2017 2.2.2017 Juha Vihavainen / University of Helsinki Juha Vihavainen / University of Helsinki