Advanced Software Engineering with C++ Templates Templates Thomas - - PowerPoint PPT Presentation

advanced software engineering with c templates
SMART_READER_LITE
LIVE PREVIEW

Advanced Software Engineering with C++ Templates Templates Thomas - - PowerPoint PPT Presentation

Advanced Software Engineering with C++ Templates Templates Thomas Gschwind <thg at zurich dot ibm dot com> Templates Polymorphisms Specialization Declaration and Use Classes and Members Ambiguities An Example (pvector)


slide-1
SLIDE 1

Advanced Software Engineering with C++ Templates

Templates

Thomas Gschwind <thgatzurichdotibmdotcom>

slide-2
SLIDE 2

Templates

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

91

§ Polymorphisms § Declaration and Use § Ambiguities § Specialization § Classes and Members § An Example (pvector)

slide-3
SLIDE 3

Types of Polymorphisms

§ “Ad-hoc”

  • Overloading
  • Statically resolved by the compiler (using argument types)

§ Dynamic

  • Using virtual member functions
  • Method to be invoked identified during run-time

(using a virtual method table)

§ Static or Parametric

  • Using templates
  • Function to be invoked identified statically
  • Concrete Functions/Classes are generated for the individual parameter types
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

92

slide-4
SLIDE 4

Templates – Why?

§ Allow to implement a function or class for a set of types and not just a ”single” hard-coded type

  • Writing min, max, swap, gcd, and lcm for all kinds of types is tedious
  • Sort of like Lisp, Smalltalk, Python, Ruby, you name it…
  • Just more efficiently

§ Support generic programming

  • Many functions are the same independently of the data type
  • Can influence the compiler’s code generation with specially crafted

templates

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

93

slide-5
SLIDE 5

Templates: Declaration and Definition

§ Specify type as additional compile-time parameters

  • Types used with this template have to provide the routines used by the

template

  • In this case, the comparison operator and a copy constructor

§ Are checked and resolved statically (during compile time)

  • Function calls can be resolved during compilation time

§ The definition must be available to the compiler

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

94

template<class T> T min(T a, T b) { return a<b ? a : b; }

This is “old style”, typename is “more” correct, but many people still prefer class. If you use an antiquated C++ compiler you may have to use class.

slide-6
SLIDE 6

Templates: Use

§ When invoking templates we can specify as additional (compile- time) parameter the type of the template to use

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

97

template<typename T> T min(T a, T b) { return a<b?a:b; } const double pi=3.141596; void f() { min<double>(2.718282, 1.0); min<char>('a', 'z'); min<int>(1, 26); min<double>(pi, 2.718282); min<int>('a', 26); min<double>(2.718282, 1); }

slide-7
SLIDE 7

Templates: Use (cont’d)

§ In most cases, template parameters are deduced by the compiler

  • Deduction must be unambiguous
  • Otherwise, the ambiguity needs to be resolved manually
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

98

template<typename T> inline T min(T a, T b) { return a<b?a:b; } const double pi=3.141596; void f() { min(2.718282, 1.0); min('a', 'z'); min(1, 26); min(pi, 2.718282); min('a', 26); min(2.718282, 1); } template<typename T> inline T min(T a, T b) { return a<b?a:b; } const double pi=3.141596; void f() { min(2.718282, 1.0); // ok min('a', 'z'); // ok min(1, 26); // ok min(pi, 2.718282); // ok min('a', 26); // error, ambiguous min(2.718282, 1); // error, ambiguous }

slide-8
SLIDE 8

Templates: Resolving Ambiguities

§ Unlike “normal” functions, there is no implicit conversion for parameters passed to templates § Explicit

  • If necessary

min<int>('a', 26);

  • Or even if unnecessary

min<const double>(pi, 2.718282);

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

100

slide-9
SLIDE 9

Mixing Templates and Non-Templates

§ Templates and non-templates can be mixed § Can define a template-based function min § And define a non template-based function min at the same time § Non-templates are preferred over templates if no type conversion necessary

template<typename T> T min(T a, T b) { return a<b ? a : b; } double min(double a, double b) { return a<b ? a : b; }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

101

slide-10
SLIDE 10

Templates: Resolving Ambiguities (cont‘d)

§ We can create separate helper functions

  • Helper functions may be based on the underlying template

§ This approach not only looks tedious but is also error-prone, clumsy, …

int min(int x, int y) { return min<int>(x, y); } double min(double x, double y) { return min<double>(x, y); }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

102

slide-11
SLIDE 11

min Template – A Problem?

§ What happens if we use it with (C-style) strings? § Based on the behavior of the

  • ther data types, we would

expect a lexicographical comparison of the arguments § However, compares the addresses where the strings are stored

  • Returns the string stored at the

smaller address

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

103

cout << min("Hello", "World") << endl; World Hello 0x1000 0x2000 Memory

slide-12
SLIDE 12

Specialization (1st Attempt)

§ Templates and non-templates can be mixed § Define a non template-based function min for C strings

template<typename T> T min(T a, T b) { return a<b ? a : b; } char *min(char *a, char *b) { return strcmp(a, b)<0 ? a : b; } const char *min(const char *a, const char *b) { return strcmp(a, b)<0 ? a : b; } #include "min.h" void foo(char *x, char *y, const char *z) { cout << min(x,y) << endl; cout << min(x,z) << endl; cout << min<const char*>(x,z) << endl; } // yes // yes // compiles but no We are asking for the template, so we get the template …

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

104

slide-13
SLIDE 13

Template Specialization (2nd and Final Attempt)

§ C++ allows us to specialize an existing template for specific types

template<typename T> T min(T a, T b) { return a<b ? a : b; } template<> char *min<char *>(char *a, char *b) { return strcmp(a, b)<0 ? a : b; } template<> const char *min<const char *>(const char *a, const char *b) { return strcmp(a, b)<0 ? a : b; } #include "min.h" void foo(char *x, char *y, const char *z) { cout << min(x, y) << endl; // yes cout << min(x, z) << endl; // error cout << min<const char*>(x, z) << endl; // yes }

Compiler error; as we discussed, there is no implicit parameter conversions for templates.

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

105

slide-14
SLIDE 14

Templates: Classes and Members

§ Works exactly the same § Simply put

template <typename T, typename U, …>

in front of the declaration § It is even OK, to introduce new template parameters for individual member functions § Before C++17 no template parameter deduction for constructors

  • Template arguments need to be invoked when constructing an object

pair<int, bool>(1, false)

  • Helper functions such as make_pair(1, false)

§ Template parameter deduction of constructors [C++17]

  • Allows developers to write pair(1, false)
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

106

slide-15
SLIDE 15

A Persistent pvector Class

§ We want to implement a persistent version of C++’s vector class § Reads all elements from a file in the constructor § Writes all elements back to the file in the destructor

template<typename T> class pvector { string filename; vector<T> v; … public: pvector(string fname) : filename(fname) { readvector(); } ~pvector() { writevector(); } void push_back(const T &el) { v.push_back(el); } void pop_back() { v.pop_back(); } …

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

107

slide-16
SLIDE 16

A Persistent pvector Class (cont’d)

template<typename T> class pvector { string filename; vector<T> v; void readvector() { ifstream ifs(filename); for(;;) { T x; ifs >> x; if(!ifs.good()) break; v.push_back(x); } } void writevector() {

  • fstream ofs(filename);

typename vector<T>::iterator fst=v.begin(), lst=v.end(); while(fst!=lst) ofs << *fst++ << endl; } …

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

108

OR starting with C++11, simply: for (const T &elem : v) ofs << elem << endl;

slide-17
SLIDE 17

A Persistent pvector Class (cont’d)

§ What happens if we pass the pvector around? § Hence, maybe we want to disable the copy-constructor for

pvector<T>

void foo(pvector<int> pv) { if(pv.size()>0) cout << pv[0] << endl; pv.push_back(17); } int main(int argc, char *argv[]) { pvector<int> pv("/tmp/pvector-int.txt"); foo(pv); }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

109

slide-18
SLIDE 18

BREAK?

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

110

slide-19
SLIDE 19

Advanced Software Engineering with C++ Templates

Separate Compilation

Thomas Gschwind <thgatzurichdotibmdotcom>

slide-20
SLIDE 20

Separate Compilation

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

112

§ Compared to Java § Variables § Routines (Functions & Operators) § Types (Structures, Classes) § Makefiles

slide-21
SLIDE 21

Separate Compilation

§ Why?

  • Having only one source file is unrealistic
  • Break the code up into its logical structure
  • Reduction of compile time
  • Only changed parts need to be recompiled

§ How?

  • Use multiple source files
  • Compiler needs to know about
  • Functions and variables provided by other compilation units
  • Their signatures and types
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

113

slide-22
SLIDE 22

Separate Compilation in Java

§ Each Java source file is compiled into a class file § If a Java class invokes a method of another class, the compiler consults that other class file to

  • Determine whether the class provides the requested method
  • Determine whether the class implements the requested interface
  • etc.
  • To achieve that, the .class file contains the entire interface

§ That’s why in Java, the compiler needs the class path § Finally, all class files are loaded by the Java Virtual Machine (and “linked”) § Java source code can be reconstructed from .class file (see Java Decompiler: jd, jad)

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

114

slide-23
SLIDE 23

Some Java Trivia

§ Let us write Hello World in Java § In order to simplify the reconfiguration (e.g., translation)

  • Put all the constants into one Java file
  • Put the complex application code into another
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

115

public class Const { public static final String msg = "Hello World!"; } public class Cool { public static void main(String[] args) { System.out.println(Const.msg); } }

slide-24
SLIDE 24

Some Java Trivia

§ Now compile both Java files and run Cool § Change the msg in Const.java, recompile Const.java, and run Cool

public class Const { public static final String msg="Hello World!"; } public class Cool { public static void main(String[] args) { System.out.println(Const.msg); } }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

116

slide-25
SLIDE 25

Some Java Trivia

§ Now compile both Java files and run Cool § Change the msg in Const.java, recompile Const.java, and run Cool § Cool still prints the old message! Why?

  • javac inlines constants
  • And according to the Java specification that’s legal
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

117

public class Const { public static final String msg="Hello World!"; } public class Cool { public static void main(String[] args) { System.out.println(Const.msg); } }

slide-26
SLIDE 26

Separate Compilation in C++

§ By convention, each source file is compiled into an object file § Object files provide the “minimum” necessary to execute the code § Object files do not provide enough information for the compiler to identify

  • Functions provided by another compilation unit
  • Layout of a user-defined type

§ Object files are not used during the compilation

  • C++ and C use “header” files to store the interfaces of the object file
  • These files need to be supplied by the developer

§ In C/C++, we have the include path instead

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

118

Strictly speaking, that’s not true as we will learn

slide-27
SLIDE 27

Header Files

§ C++ uses so-called header files for separate compilation § The header file can be viewed as the object file’s interface § Hence, header files are another encapsulation mechanism

  • They describe the interface(s) provided by the object files
  • Describe everything that should be exported to other compilation units

§ What goes into the header file?

  • “Everything” that should be exported (i.e., used in other files)
  • “Nothing” that causes the compiler to immediately generate code
  • Except, for a small number of exceptions
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

119

slide-28
SLIDE 28

Header Files: Inclusion

§ Header files need to be included

  • Tells the compiler what external artifacts we will be using

§ Possibly, the string header also includes iostream

  • It defines input/output functions and needs the types defined by iostream

§ Need a mechanism to prevent headers from being included multiple times

  • C++ uses the same mechanism as C
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

120

#include <iostream> #include <string> …

slide-29
SLIDE 29

Header Files: Prevent Multiple Inclusion (Guard)

§ Header files need protection from being included multiple times § Otherwise, this may cause compile errors

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

121

#include "vars.h" int my_dumb_global_variable=17; const double e=2.718281; #ifndef VARS_H_ #define VARS_H_ extern int my_dumb_global_variable; extern const double e; const double pi=3.141596; #endif

if VARS_H_ is not defined process the following lines define _VARS_H end the last open #if… section Process the file “vars.h” This pattern ensures that header files won’t be included multiple times

vars.h vars.cc

slide-30
SLIDE 30

Header Files: Prevents Multiple Inclusions (#pragma)

§ An alternative to the guard statement is to use #pragma once in your header files

  • Although a non-standard, it is widely supported
  • Serves the same effect, less code to write
  • Can be more efficient during compilation, file needs to be opened only once
  • No name-clashes
  • Compiler may not always be able to identify whether two files are equal

(hard links, symbolic links, multiple filesystem mounts, etc.)

§ My suggestion

  • Stick to the standard
  • Use a system to uniquely generate the guard name
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

122

slide-31
SLIDE 31

Header Files: Variables

§ Variables

  • Declaration goes into the header (mark variable as extern!)

(if variable is to be accessed elsewhere)

  • Definition goes into the implementation file (allocates memory)

§ Constant Variables

  • Declaration goes into the header

(if variable is to be accessed elsewhere)

  • Definition goes either into the header or the implementation file
  • If in the header, definition may be allocated multiple times
  • No problems for individual values (constant and small)
  • Be careful with large constants such as large constant arrays
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

123

slide-32
SLIDE 32

Header Files: Variables Example

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

124

#include "vars.h" int my_dumb_global_variable=17; const int primes[]={2, 3, 5,…, 1234567891}; #ifndef VARS_H_ #define VARS_H_ extern int my_dumb_global_variable; const double pi=3.141596; extern const int[] primes; #endif

Use extern to declare a variable to be defined elsewhere. No memory will be allocated for the variable

vars.h vars.cc

Constants may be defined in the header or declared like other variables. Include the header (for consistency checking) Variables are defined in the implementation file. Do not repeat constants defined in the header.

slide-33
SLIDE 33

Header Files: Functions

§ Functions

  • The declaration of the function goes into the header
  • Definition goes into the implementation file

§ Inline Functions

  • If they are to be inlined in the corresponding implementation file only,

treat them like functions

  • If they are to be inlined globally (typical),

declaration and definition go into the header file

  • Necessary for the compiler to know

the implementation to be use instead of the function call

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

125

slide-34
SLIDE 34
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

126

Header Files: Functions Example

#include "util.h"

int gcf(int a, int b) {

if (a<b) swap(a,b); while (b!=0) { a=a-b; if (a<b) swap(a,b); } return a; }

#ifndef UTIL_H_ #define UTIL_H_

inline void swap(int &a, int &b) {

int c=a; a=b; b=c; }

extern int gcf(int a, int b); inline int lcm(int a, int b) {

return (a/gcf(a,b))*b; }

#endif

util.h util.cc

Inline functions are declared and defined in the header file. Use extern to declare a function. Extern for function declarations is

  • ptional. If there is no function

body, it cannot be a definition. Functions are defined in the implementation file. Do not repeat inline functions defined in the header.

slide-35
SLIDE 35

Inline Functions

§ We can declare functions as inline

  • As part of the exercise you have probably seen that most compilers treat this

just as a hint (or ignore it altogether since they know better)

  • However, the compiler can only inline the function, if its implementation is

visible to the compiler which is why inline functions go into the header

§ However, newer compilers support link-time-optimization

  • The compiler (also) stores an internal representation of your program in the
  • bject file
  • When linking the program, the compiler performs additional link-time-
  • ptimizations such as inlining functions

§ For the time being, it is not a lot of effort to put small functions as inline functions to the header

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

127

slide-36
SLIDE 36

Header Files: Types (typedef, struct, class)

§ Type declarations and definitions go into the header

  • The layout of the type needs to be known to the compiler

in all compilation units that need to allocate the type

§ For member functions, the same rules as for functions apply

  • Member declarations into the header
  • Member definitions (except for the ones to be inlined) into the

implementation file

  • All members of a class even if they should not be visible outside the

compilation unit need to be declared as part of the type definition

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

128

slide-37
SLIDE 37
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

129

Header Files: class Example

class fraction { int c; int d; public: fraction(int cntr=0, int denom=1) : c(cntr), d(denom) { /*void*/ } fraction operator*(const fraction &b); fraction operator/(fraction b) { swap(b.c, b.d); return (*this)*b; } }; #include "fraction.h" #include "util.h" fraction::fraction operator*(const fraction &b) { fraction r; int f1=gcf(this->c,b.d), f2=gcf(b.c,this->d); r.c=(this->c/f1)*(b.c/f2); r.d=(this->d/f2)*(b.d/f1); return r; }

  • perator/ is an implicitly inline

member, inline functions go into the header file.

fraction.h fraction.cc

The complete layout of a type (public, protected, private members) go into the header file.

slide-38
SLIDE 38
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

130

Header Files: Templates

§ Type declaration and definition go into the header

  • The code for a template is generated when it is parameterized
  • Hence, the compiler needs the full code to instantiate the template

§ If the template is only to be parameterized with a small set of types

  • Can treat template functions and template classes like normal functions and

classes

  • Need to instantiate the class in an implementation file that has access to the

full template definitions (for instance, template class pvector<string>;)

slide-39
SLIDE 39

main program

§ Include header files

  • System header files first allows to

find compile errors in header more easily

  • Own header files first allows to

find missing definitions in header more easily

§ Compile each file § Put dependencies into Makefile

  • If implementation file changes, it

needs to be recompiled

  • If a header file changes, layouts
  • f types may have changed, all

files including it need to be recompiled

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

131

#include <stdlib.h> #include <iostream> #include "fraction.h" #include "util.h" #include "vars.h" void main(int argc, char *argv[]) { int arg=atoi(argv[1]); cout << arg << "^2*pi=“ << arg*arg*pi << endl; cout << "e=" << e << endl; cout << gcd(atoi(argv[1]), atoi(argv[2])) << endl; cout << lcm(atoi(argv[1]), atoi(argv[2])) << endl; … // use of fraction data type }

slide-40
SLIDE 40

Makefile

all: main main: main.o fraction.o util.o vars.o g++ -o main main.o fraction.o util.o vars.o main.o: main.cc fraction.h util.h vars.h g++ -c main.cc fraction.o: fraction.cc fraction.h util.h g++ -c fraction.cc util.o: util.cc util.h g++ -c util.cc vars.o: vars.cc vars.h g++ -c vars.cc

Makefile

main.cc fraction.cc fraction.h util.h vars.h main.o fraction.o util.o vars.o main util.cc vars.cc Link the final executable (could also use ldd but tedious)

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

132

slide-41
SLIDE 41

Useful Build Tools

§ gcc: not only compiles and links files

  • Also analyzes sources and generates dependencies between them

(Checkout the -M… options)

  • Also allows to analyze java files for the dependencies between them

§ ld: link object files

  • For C++ files, you need to include the C++ library as well (stdc++)

§ nm: list symbols in an object file or program

  • Defined, undefined, which section, etc.

§ ldd, otool –L: list libraries needed by an object file

  • Simply list the shared libraries the object file is dependent on
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

133

slide-42
SLIDE 42
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

134

Makefiles (made easy)

§ As mentioned before, gcc allows to generate source dependencies § This Makefile can be used as a generic starter for your Makefile

CXXFLAGS=... CXXFLAGS+=-Wall -Wextra -Werror OBJS=main.o # "main" file OBJS+=fraction.o ... # others… all: main clean: rm -f main *.o distclean: clean rm -f .depend/*.d rm -f *~ ...

slide-43
SLIDE 43
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

135

Makefiles (cont’d)

...

  • include $(addprefix .depend/,$(OBJS:.o=.d))

%.o: %.cc g++ $(CXXFLAGS) -c -o $@ $*.cc @g++ -MM $(CXXFLAGS) -c $*.cc >.depend/$*.d main: $(OBJS) g++ $(LDFLAGS) -o $@ $(OBJS)

slide-44
SLIDE 44

BREAK?

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

136

slide-45
SLIDE 45

Advanced Software Engineering with C++ Templates

Memory Management

Thomas Gschwind <thgatzurichdotibmdotcom>

slide-46
SLIDE 46

Memory Management

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

138

§ Allocation & Deallocation § Stack § Variables (Pointers, Arrays, References) § Heap § Memory and Classes

slide-47
SLIDE 47

Memory Management: Java vs. C++

§ In Java

  • Primitive types are stored on the stack
  • Non primitive types are always stored on the heap

(only their references are stored on the stack)

  • Memory is automatically freed by the garbage collector

§ In C++

  • Built-in types and objects can be stored on the stack and heap
  • C++ supports references and pointers; both can refer/point to objects and

built-in types both on the stack and the heap

  • Stack memory is managed automatically
  • Heap memory needs to be allocated and freed explicitly

(with delete and delete[])

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

139

slide-48
SLIDE 48
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

140

Functions: Parameter Passing

§ Call by Value

  • Argument to be passed copied from the caller’s scope into the callee’s scope
  • Callee operates on its own copy

§ Call by Reference/Pointer

  • Callee receives a references to the argument passed by the caller
  • Callee operates on caller’s copy

§ C++/C

  • All parameters can be passed by value, by pointer, or in C++ also by reference

§ Java

  • Primitive types are passed by value
  • Class instances are passed by reference

§ C#

  • Value types (primitives and structs) by value or reference
  • Class instances by reference
slide-49
SLIDE 49

Memory Organization

Memory needs to store A typical layout looks like this

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

141

§ The program § Global variables § Local variables (on the stack) § Data allocated dynamically with new (on the heap)

Memory

0xffff:

. . . . Stack

0x0000:

Heap . . . Global Variables . . Program . .

slide-50
SLIDE 50

The Stack

§ Stores local variables, return addresses, etc. § Right side shows the (simplified) stack after fact(2) has been invoked

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

142

int fact(int n) { int m=n-1; if (n<=2) return n; else return n*fact(m); } int main() { cout << "fact(4)=" << fact(4) << endl; return 0; }

0x0ff8: 0x0ffc: n==4, m==3 “line 8” . . main() - code . . 0x0ff0: “line 4” n==3, m==2 “line 4” n==2, m==1 0x0fec: 0x0fe8: 0x0fe4: 0x1000: result result result 0x0fdc: 0x0fd8: 0x0fd0: fact(4) fact(3) fact(2)

1 2 3 4 5 6 7 8 9 10

slide-51
SLIDE 51

Pointers (TYPE*)

§ Pointers are a fundamental concept of C++ § Pointers should be used sparsely and carefully § A pointer points to a value or object stored anywhere in memory § Since pointers can point to different TYPEs of values, there are different types of pointers denoted by TYPE* § A pointer is similar to an iterator iterating over a collection of elements of type TYPE

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

143

slide-52
SLIDE 52

Pointer Operations

§ &-Operator

  • Obtain the address where a value is stored in memory (lvalue)
  • Returns a pointer to the type of the lvalue
  • &(lvalue)

§ *-Operator

  • Dereference a pointer (i.e., manipulate the memory that the pointer points

to)

  • Return the type of the value the pointer points to
  • *(expr)
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

144

An lvalue (left value) is an expression that can occur on the left or the right hand side

  • f an assignment expression. An rvalue is

an expression that can only occur on the right hand side.

slide-53
SLIDE 53

Pointers (cont’d)

§ Pointers store an address § This is visible to the developer § The type of the pointer indicates the type of object stored at the address

Address-Space

0x0ff8: 0x0ffc: b==5 a==3 . . . . main() . . . . . . . 0x0ff4: pa==? a==9

int main() { int a=3; int b=5; int *pa; pa=&b; pa=&a; // ok *pa=9; // ok }

pa==0x0ff8 pa==0x0ffc 0x1000:

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

145

slide-54
SLIDE 54

Modifying Arguments with Pointers

§ Implement a routine that exchanges the value of two arguments § Arguments must be an lvalue § Invoked with c_swap(&var1, &var2); § In Java, this is impossible, arguments need to be wrapped within an object

void c_swap(int *x, int *y) { int z=*x; *x=*y; *y=z; } int a=3, b=5; c_swap(&a, &b);

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

146

slide-55
SLIDE 55

References (TYPE&)

§ Similar to pointers – sometimes more elegant § However, like pointers they should be used

  • Sparsely and
  • Carefully

§ A reference refers to a value or object stored in memory, it is another name (alias) for a given value or object stored in memory § Unlike a pointer, it cannot be changed to refer to a different location

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

147

slide-56
SLIDE 56

References (cont’d)

§ References are similar to pointers § Except their implementation is “invisible”

Address-Space

0x6f04: 0x6f08: b==5 a==3 . . . . main() . . . . . . . 0x6f00:

int main() { int a=3 int b=5; int &pa=a; pa=7; // ok //&pa=b; // error pa=b; // ok }

pa/a==3 pa/a==7 pa/a==5

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

148

slide-57
SLIDE 57

Modifying an Argument with References

§ Implement a routine that exchanges the value of two arguments § Argument must be an lvalue § Invoked with swap(var1, var2); § Similar to VAR parameter in Pascal § In Java, this is impossible, in C#, however, it is possible Int a =3, b =5; Swap(a, b); // a==5, b==3

void swap(int &a, int &b) { int c=a; a=b; b=c; }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

149

slide-58
SLIDE 58

Returning References

§ Functions may also return references § Allows the function to be used as lvalue

class fraction { public: … // conversion fraction to double

  • perator double() { return (double)c/d; }

// references as return value int &counter() { return c; } int &denominator() { return d; } }; void normalize(fraction &a) { int f = gcf(a.counter(), a.denominator()); a.counter() = a.counter() / f; a.denominator() /= f; }

counter() and denominator() may now be used on the left side of operator= (i.e., as lvalue) However, this may make it harder to change the internal representation of fraction numbers in the future

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

150

slide-59
SLIDE 59

Use References with Care

§ References have the same characteristics as a pointer

  • The variable a reference point should exist as long as the reference itself
  • Never return a reference to a local variable (unless static)!
  • (BTW, avoid static local variables, they are like global variables)

§ References are taken implicitly

  • Makes their code nicer to read
  • BUT easy to overlook that they pose the same risks as pointers
  • May be generated “by accident”

§ The Google Coding Style suggests to avoid references as return values and instead to stick to pointers

  • Advantage, have to write return &variable;
  • Disadvantage, may not always be intuitive
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

151

slide-60
SLIDE 60

Commonly Used (Safe) Patterns

§ Function references elements passed to it by caller

  • swap(int &a, int &b)
  • If a and b are valid in caller scope, they “must be” valid in callee’s scope
  • Caveat: make sure that it is obvious to the caller that a and b may be modified
  • print_vector(const vector<string> &v)
  • Almost as above, except with const we promise that v will not be modified
  • Avoids duplication of v which is otherwise passed by value

(very common pattern)

§ Function returns reference to element passed to it

  • ostream &operator<<(ostream &os, const T &element)
  • Same argument as above we return to caller a reference to an object that is his

§ Member function returns reference to element of its class

  • int &fraction::counter()

T &vector::operator[](size_t index)

  • Actually, same as above, since this is implicitly passed to the member function
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

152

slide-61
SLIDE 61

Arrays

§ Arrays provide memory for several values of the same type § In C++ an array is typically equivalent to a pointer of the first element of the array

0x0ff8: 0x0ffc: buf[2]==? buf[3]==? . . main() . . 0x0ff4: buf[1]==? buf[0]==? bufp==0x0fec 0x0ff0: 0x0fec: 0x0fe8: 0x1000:

void foo() { int buf[4]; int *bufp=buf; // ok buf[0]=3; // ok *buf=3; // same *bufp=*buf; // same ++bufp; *bufp=*buf+1; }

buf[0]==3 “line 8” bufp==0x0ff0 buf[1]==4

buf

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

153

slide-62
SLIDE 62

Arrays (Be Careful)

§ Arrays are not range checked (buffer-overflow) § C++ happily assigns a value to buf[4] § Arrays “cannot” be returned as the result of a function § You may want to use the following alternatives in C++

  • std::array<T, N>: Fixed size array of type T with N elements
  • std::vector<T>: Dynamically growing “array” of type T
  • Both provide bound checking when accessed with at(…)
  • Both can be returned as the result of a function
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

154

slide-63
SLIDE 63

The Heap

§ Stores non-local and non-global data § If memory needs to be allocated during runtime (e.g., linked lists, large arrays, …) § Memory needs to be explicitly allocated (like new like in Java) § For returning large user-defined types or arrays from routines (although consider alternatives) § When allocating data on the heap, think about its ownership and life-cycle

  • Generally, whoever allocates it, should

deallocate it

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

155

Memory

0xffff:

. . . . Stack

0x0000:

Heap . . . Global Variables . . Program . .

slide-64
SLIDE 64

Memory Allocation & Deallocation

§ “No” garbage collection in C/C++

  • Memory needs to be explicitly

allocated (new, new[]) and freed (delete, delete[])

  • Some lazy and/or old-fashioned C programmers still use malloc when they

want uninitialized memory (there can be an advantage to this: realloc)

  • The proper way of allocating uninitialized memory, however, is

::operator new (size_t bytes)

§ Error handling

  • bad_alloc will be thrown (new …),
  • or NULL is returned (new (nothrow) …)

§ Initialization

“Unfortunately, overuse of new (and of pointers and references) seems to be an increasing problem.” Bjarne Stroustrup

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

156

slide-65
SLIDE 65

Returning an Array

§ An array per se is a pointer

  • Cannot return the entire array
  • Can only return the pointer

Memory

0xffff:

. . . .

0x0000:

int* foo2(int n) { int *buf=new int[n]; for (int i=0; i<n; ++i) { buf[i]=i*i; } return buf; } void main() { int *buf=foo2(10); for (int i=0; i<10; ++i) { cout << buf[i] << endl; } delete[] buf; }

buf[2]==4 buf[3]==9 buf[1]==1 buf[0]==0

Program .

0x1000: 0x2000: buf==? “line 7” buf==0x2000 0x0ff8: 0x0ff4: 0x0ff0: 0x2004: 0x2008: 0x200c: result

buf

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

157

slide-66
SLIDE 66

Returning an Array (Style!)

§ The example has a style problem § Can you spot it?

  • Memory is allocated in foo2 and deallocated in main
  • If possible one should deallocate memory in the same method as it is

allocated

§ What are the alternatives?

  • Allocate the array in main and pass it into foo2
  • If that is not possible implement a foo2_cleanup routine that deallocates the

memory returned by foo2

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

158

slide-67
SLIDE 67

Returning an Array with Nice Memory Management

§ Frequently, in C, when a function f allocates memory for us, there is a sister function f’ that releases the memory allocated by f

(e.g., getaddrinfo, freeaddrinfo)

int* new_foo2(int n) {

int *buf=new int[n]; for(int i=0; i<n; ++i) { buf[i]=i*i; } return buf; }

void delete_foo2(int *buf) {

delete[] buf; } void main() {

int *buf=new_foo2(10);

for(int i=0; i<10; ++i) { cout << buf[i] << endl; }

delete_foo2(buf); }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

159

slide-68
SLIDE 68

C++ auto_ptr<T> (deprecated since C++11)

§ C++ does not perform garbage collection but has wrappers that come close

  • auto_ptr<T>

Delete object pointed to when ptr is destructed

void foo() { auto_ptr<int> pi (new int); *pi=17; cout << "*" << pi.get() << "=" << *pi << endl; auto_ptr<int> pj(pi); // transfer ownership; pi points to NULL *pj=19; cout << "*" << pi.get() << endl; // displays 0 cout << "*" << pj.get() << "=" << *pj << endl; } // deallocate the integer

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

160

Works the same with C++11 unique_ptr except use pj(pi.release()) to transfer ownership

slide-69
SLIDE 69

C++11: Memory Management

§ More versatile pointer wrappers

  • auto_ptr<T> depending on the context should be replaced with

unique_ptr<T> or shared_ptr<T>

§ The following “pointers” provided by the Standard Library help

  • unique_ptr<T>

Delete object pointed to when unique_ptr is destructed

  • shared_ptr<T>

Delete object pointed to by shared_ptr when this is the “last” pointer pointing to the object – works similar to the smart_ptr exercise

  • weak_ptr<T>

Useful in combination with shared_ptr if cyclic structures are used, allows to break up cycles, need to be converted to shared_ptr before object may be accessed, see documentation for details

§ Don’t use them as all-round solution

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

161

slide-70
SLIDE 70

C++11: Returning an Array

§ unique_ptr and shared_ptr can be used to return objects § The pointers will destruct the object when “they” no longer point to it

unique_ptr<int[]> make_foo3(int n) { unique_ptr p{new int[n]}; for(int i=0; i<n; ++i) { p[i]=i*i; } return p; } void main() { auto buf = make_foo3(10); for(int i=0; i<10; ++i) { cout << buf[i] << endl; } }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

162

slide-71
SLIDE 71

Frequently, a C++ vector will Work Best?

§ The previous code is great if you insist on C-style memory management § Why not simply return a vector<int>

  • No worries about memory management
  • More readable, more C++-like

vector<int> foo2(int n) {

vector<int> res(n); for(int i=0; i<n; ++i) { res[i] = i*i; } return res; } void main() {

vector<int> buf=foo2(10);

for(int i=0; i<10; ++i) { cout << buf[i] << endl;

} }

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

163

Creates n default ints; if that is a problem, use: vector<int> res; res.reserve(n); for(int i=0; i<n; ++i) { res.emplace_back(i*i); } return res; The reserve(…) member does not initialize the extra memory.

slide-72
SLIDE 72

164

Summary

§ Templates

  • Definition
  • Use
  • Specialization

§ Separate Compilation § Memory Organization & Management

  • Allocation & Deallocation
  • Stack
  • Variables (Pointers, Arrays, References)
  • Heap
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.
slide-73
SLIDE 73

Exercise L2.1: pvector<T>

§ Implement the persistent vector data type. § Experiment with the persistent vector and use it in combination with different data types. What do you observe? Why do you

  • bserve that behavior? How can it be changed?

§ What happens if we pass the pvector<T> around?

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

165

slide-74
SLIDE 74

Exercise L2.2: h vs cc

§ Which line belongs into the header file, respectively into the implementation file? Why?

char ch; string s; extern int error_number; static double sq(double); int count=1; const double pi=3.2; // according to Indiana Pi Bill struct fraction { int c; int d; }; char *prog[]={"echo","hello","world!",NULL}; extern "C" void c_swap(int *a, int *b); double sqrt(double); void swap(int &a, int &b) { int c=a; a=b; b=c; } template<typename T> T add(T a, T b) { return a+b; } namespace { int a; } struct user;

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

166

slide-75
SLIDE 75

Exercise L2.3: Template-based RPN (to be cont’d)

§ Upgrade your RPN calculator

  • Change your implementation into a template such that RPN<T>() will create

your RPN calculator to work with type T; ensure you can use int, double, fraction as type T

  • Make use of your pvector class to store the numbers the user pushes onto

the stack persistently (i.e., when you terminate your calculator with numbers on the stack that they reappear when you restart it)

  • Make use of separate compilation in combination with a Makefile
  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

167

slide-76
SLIDE 76

Exercise L2.4: Connect 4 (to be cont’d)

§ Implement a template-based version of Connect 4. Connect 4 builds on a playing field composed out of 7 columns each having 6

  • rows. When a player puts a stone into a column, gravity pulls the

stone towards the lowest unoccupied column. The player who first has 4 stones in a row (horizontally, vertically, diagonally) wins. § After each turn display the game field using simple ASCII graphics. Implement the game in such a way that players can be exchanged easily using templates. § The precise interfaces to follow will be published at the lecture’s

  • homepage. It is important that you follow these interfaces

religiously.

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

168

slide-77
SLIDE 77

Exercise L2.5: Under the Hood

§ Have a look at the following swap routines

  • void swap(int &a, int &b) { int c=a; a=b; b=c; }
  • void c_swap(int *a, int *b) { int c=*a; *a=*b; *b=c; }

§ Let the compiler compile the code but ask the compiler to stop at the assembly stage $ gcc -S -o source.s source.cc § Compare the assembly code, what do you observe? § How do you interpret the difference(s)?

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

169

slide-78
SLIDE 78

Next Lecture

§ Templates: Traits § Standard Library: Algorithms § Standard Library: Input and Output Have a nice weekend, see you in two week

  • Th. Gschwind. Advanced Software Engineering with C++ Templates.

172