Presentation is loading. Please wait.

Presentation is loading. Please wait.

Accelerated C/C++ Advanced OOP CS 440/540 Spring 2015 Kenneth Chiu.

Similar presentations


Presentation on theme: "Accelerated C/C++ Advanced OOP CS 440/540 Spring 2015 Kenneth Chiu."— Presentation transcript:

1 Accelerated C/C++ Advanced OOP CS 440/540 Spring 2015 Kenneth Chiu

2 Purpose I’m assuming all of you have had a first-pass in C++. – Basic style – Basic programming approach Learn iteratively. Content-based on what has tripped me up in the past. Why is C++ the way it is? Sometimes a language may have a mistake. – What is a mistake in a language?

3 What Is A Language? What is a computer language? – HTML? – PHP? – XML? – Excel Macros? “Turing complete” – Can compute anything that a TM can compute.

4 Compilation Process What happens when we compile? – What is object code? Invoked via a front-end driver: – Run the preprocessor. – Run the compiler. – Run the assembler. – Run the linker. What happens when you run a compiled program? – OS loads the file into memory. – Sets up various memory regions. – May do some runtime linking/relocation. – Jump to main.

5 Language Runtime Close correspondence between machine and source. – i = 2 + j; Not a close correspondence. – if (typeid(A) == typeid(B)) { … } Such machine code is said to be part of the language runtime. Source code that causes no machine code to be generated?

6 Compilation Process What is a compiled language? – Is “compiled” or “interpreted” an inherent property of a language? – How does the hardware affect the distinction? – How do you decide whether to interpret or compile? What happens when we compile? – What is object code? Compilers are usually invoked via a front-end driver that orchestrates the stages. For example, g++ will: – Run the preprocessor. – Run the compiler. – Run the assembler. – Run the linker.

7 Types of Violations of the Standard What is a language standard, what does it specify? – Does it tell you what you can or cannot do? Not really. – It specifies constraints on the language. It says, if you do A, then B happens. – It’s a contract, essentially. What is a “violation” of the standard? – It’s imprecise word, but commonly used to mean something not in accordance with some aspect of the standard. – What happens when your program violates the standard? Does it mean the program won’t compile? Will it crash? – Can a compiler also violate the standard? – Are there different ways that a program can “violate” the standard?

8 What will this print out? – #include int main() { char i = 0; i--; std::cout << (int) i << std::endl; } – Prints out -1 when compiled on remote.cs.binghamton.edu. – Is it guaranteed to print this out? In every occurrence? – How can we find out what it will print out? – The compiler vendor needs to tell you if char is signed or unsigned? Known as implementation-defined behavior. What will this print out? – void foo(int i1, int i2) { } foo(printf(“First.\n”), printf(“Second.\n”)); – Is it guaranteed to print this out? In every occurrence? – How can we find out what it will print out? – You can’t. The compiler vendor can change it at will. Known as unspecified behavior. What will this do? – int *a = 0; *a = 1; – Anything could happen. Anything. – “Demons could fly out of your nose!” – Known as undefined behavior.

9 Implications of “undefined behavior” for the Implementer As the implementer, what do you do if the specification says that the result is undefined behavior? For example, let’s say the function below is specified as: – void foo(int *); If the pointer is null, the behavior is undefined. If the pointer does not point to the first element of an array of two integers, then the behavior is undefined.

10 Compile-Time vs. Run-Time What kind of error is better? For a given error, there’s no advantage to making it run-time. However, to turn that run-time error into a compile-time error usually means using a strict, statically-typed language. Those languages are usually thought of as being not as flexible.

11 Preprocessor #include “A.hpp” – #include #define macro(a, b) #if – #if FOO == 3 – #if defined(a) – #endif – #else, #elif #ifdef, #ifndef #error, #pragma __LINE__ (integer literal), __FILE__ (string literal), __DATE__ (string literal), __TIME__ (string literal) __cplusplus # (stringification) and ## (token gluing) in expansions [Show]

12 -E (option to show results after preprocessing) [Show preprocessor_output_option.] Line continuation is a backslash at the end. (Make sure you don’t have a space after the backslash.) What’s wrong with this? – #define MY_MACRO(t) \ void foo_##t() { \ // This is a comment. \ call_something(); \ }

13 Multi-line macros: – #define macro(x) \ cout << x << endl; \ cout << “DEBUGGING” << endl; – Good? – if (condition) macro(my_var); – #define macro(x) \ do { \ cout << x << endl; \ /* Etc. */ \ } while (0) – Why did we leave off the semicolon at the end?

14 Macros can call other macros, but cannot be used recursively.

15 Suppose you have code that should compile on both Linux and Win32, but you need to call a different function in each. What do you do? – Why not just have two versions of your source code? Conditional compilation: – #ifdef __linux some_linux_func(…); #else some_win32_func(…); #endif – Is this good? – #ifdef __linux some_linux_func(…); #elif defined (__win32_preprocessor_symbol) some_win32_func(…); #else #error Unknown platform #endif

16 Predefined identifiers: These are not macros – __func__ : A static const character array initialized with the current function name. void some_func() { cout << __func__ << endl; } void some_other_func() { cout << __func__ << endl; } – Why aren’t these macros?

17 Variadic macros – #define foo(…) func(_VA_ARGS_) – Let’s say we wanted to print the file name and line number with all of our debug statements. – [Show debug_print.] – #include #define dbg(fmt,...) \ fprintf(stderr, "%s[%d]: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__) int main() { dbg("%d, %d", 1, 2); dbg("%d, %d, %f", 1, 2, 3.14); dbg("Uh-oh!"); }

18 Assertions Assertions are ways of “asserting” that certain things are true. – By putting in an assertion, you are saying that if the expression being asserted is not true, then something is very seriously wrong. What kind of assertions might you use here? – delet(Animal *a) { … } – Animal *pop_front(List *l) { … } To make assertions work, include this header file: – #include

19 Assert liberally. – Preconditions Any condition that before a section of code that that code relies on for correctness. – Postconditions Any condition after a section of code that that code will preserve, if it was correct. For example, in a BST, you know that the left child must be greater than or equal to the right child. – Loop invariants Any condition within a loop that your code relies on for correctness. Consider code for binary search. Let’s say that it maintains an index to the beginning of the current search region (begin_index), and a pointer to the end of the current search region (end_index). What assertion can you put in at the end of the loop? – while (...) {... assert(???); }

20 Use to check return codes. – A quick and dirty way of checking error codes. Gives you 80% of the benefit, with 5% of the effort. – ec = some_lib_or_sys_call(…); assert(ec == 0); To compile-out the assertions, define NDEBUG. – g++ -DNDEBUG foo.cpp

21 How is the assert() macro defined? – How do we find it? – #ifndef NDEBUG #define assert(e) \ ((e) ? static_cast (0) \ : fail(#e, __FILE__, __LINE__, __func__)) #elif #define assert(e) #endif What if we have an assertion that is low-cost, so we always want it to be included, even in production code? – #define check(e) \ ((e) ? static_cast (0) \ : fail(#e, __FILE__, __LINE__, __func__))

22 Assertions vs. Exceptions vs. Special Return Values What are the possible behaviors you could implement for these conditions? – Animal *find(const char *type_name); Normally returns the found Animal. What should you do if the animal is not found? – int read(int fd, char *buf, int count); Normally returns count of bytes read. What should you do if it is the end of file? – double sqrt(double x); Normally returns the square root of the number. What should you do if the number is negative? – int send_socket(int sock_fd, const char *buf, int count); Normally returns the count of the number of bytes sent. What if the network is down? – void *lookup_in_hash_table(const char *key); Normally returns the value that is found (which is a void * for this particular hash table). What if the key is not found? – void *malloc(size_t sz); What if there is no more memory?

23 Compile-Time Assertions assert() is strictly run-time. You won’t know till you run the program. How can you assert things at compile-time? – A limited number of things can be checked in the preprocessor: #define FOO 2 #if FOO < 4 … #endif #if sizeof(long) < 8 #error Type long is too small. #endif – C++11 supports static_assert, which can check basically anything that is a compile-time constant ( constexpr ). static_assert(sizeof(long) >= 8, “Type long is too small.”); – C++98 can use boost static asserts.

24 Comments How are these comments? – // Define an int variable i in the for-loop, and // initialize it to 0. Execute the for-loop as long // as i is less than the value of a.size(). At the // end of each iteration, increment i by 1. In the // body of the for-loop, multiple a[i] by 2, and // assign it to a[i]. – for (int i = 0; i < a.size(); i++) { a[i] *= 2; } – // Add 7 to x, then bitwise AND it with the bitwise // complement of 0x7. – x = (x + 7) & ~0x7; – // Call compute_y() with i and x as parameters. – compute_y(i, x); – // Initialize health to 1. – double health = 1.0;

25 Better? – // Double each element in array a. for (int i = 0; i < a.size(); i++) { a[i] *= 2; } – // Round up x to next multiple of 8. x = (x + 7) & ~0x7; – // Compute y-coordinate of ith // player given a fixed // x-coordinate. compute_y(i, x); – // Create monsters starting at // health 1.0, since health 0 means // dead. double health = 1.0;

26 Don’t say the obvious. – // Initialize x. x = 1; Do comment the non-obvious. – // Round up x to next multiple of 8 x = (x + 7) & ~0x7; How do you comment out large sections of code? – Use #if 0 to comment out large sections. It will nest. If working in a team, consider leaving your initials/name in comments that might need explanation. – // x cannot be defined as a long due to a bug // in the Solaris compiler. –ken

27 SOURCE CODE ORGANIZATION

28 C++/C Source Code Organization Why break code up into multiple files? – Ease of finding things? – Compilation speed. Only need to recompile part of the app. Known as separate compilation – Libraries – Reuse? If I put a class separately into A.cpp, it is easier to move to another application.

29 Okay, why split into header file and implementation file? What (bad) things would happen if we did not? – For libraries, the case is clear. Need declarations to tell the compiler how to call code. – What about your application? Why not put everything into A.cpp, like in Java? Suppose B.cpp needs to use class A. The compiler needs the declarations. Why not just include the whole source file? – Why need header file if already linking the library? Because the link happens after the assembly code for a call is generated. Even if the compiler knew the libraries early, it can’t find the calling information. – Why need library if already have the header file? The header file tells the compiler how to call something, but there still has to be some code there to call. Are you satisfied with these answers? What’s the meta-question here? (Why isn’t this an issue in Java?)

30 The header-file/implementation-file split is a convention. – The standard does not dictate what goes in a header file. – However, the design of C++ does strongly influence best practices. What goes in a header file? – The minimum amount necessary for the implementation (classes and/or declarations of standalone functions) to be used by other files. – In other words, you divide the code into two chunks. In the first chunk, you put everything that is needed to use your code. – Such as call it, or if a class, define an instance of the object, etc. – This is the header file (.hpp ). Everything else goes in the second chunk. – This is the implementation file (.cpp) file.

31 A.hppB.hppC.hpp A.cppmain.cppB.cppC.cpp A.omain.oB.oC.o a.out (exe) Libraries includes compiled to link

32 How many times per executable is a header file compiled? What about implementation file? – If something can go in either, should we put it in the header file or implementation file? What do these code snippets need? obj->a_member void foo(MyClass *) {} obj->foo(); Where do these go? Class definitions Function definitions Function declarations Global variable declarations Global variable definitions

33 Translation Unit Consider this code fragment from a file named foo.cpp : – … void foo() { goo(); } … Are either of these statements is clear and unambiguous? – “The call to goo() will be a syntax error if there is no declaration of it in this file.” – “The call to goo() will be a syntax error if this file doesn’t declare goo(), and this file doesn’t (recursively) include any header files that declare goo().” This suggests that we should have a new term: A translation unit is the result of reading in a file, after all processing of included files and conditional compilation. – “This will be a syntax error if there is no declaration of goo() in the translation unit.”

34 Handling Global Variables How do you use global variables when you split things into files? Does this work? File1.cpp int a; void f() { // Access a. // … } File2.cpp int a; void g() { // Access a. // … } $ g++ File1.cpp File2.cpp...

35 One Definition Rule (ODR) In C and C++, each variable can be defined only once. You can declare a global variable by using extern. – Defining (no extern ) actually creates a variable. – Declaring (by using extern ) states the existence of a variable, and indicates that it was defined somewhere else, so tells the linker to go look for it. So, a global variable should be defined in one translation unit and declared in all others that use it. How to fix previous?

36 You need to have: File1.cpp int a; void f() { // Access a. // … } File2.cpp extern int a; void g() { // Access a. // … } Of course, you should probably be more systematic about it: globals.cpp int a; double x; globals.hpp extern int a; extern double x; File1.cpp #include “globals.hpp” void f() { // Access a. // … } File2.cpp #include “globals.hpp” void g() { // Access a. // … } $ g++ globals.cpp File1.cpp File2.cpp...

37 There is a lot of redundancy between globals.hpp and globals.cpp. Imagine if it were a very large file. Anyway to avoid it? globals.cpp int a; double x; //... // Zillions of them globals.hpp extern int a; extern double x; //... // Zillions of them

38 globals.cpp #define XYZZY_GLOBALS_EXTERN #include “globals.hpp” globals.hpp #ifndef XYZZY_GLOBALS_HPP #define XYZZY_GLOBALS_HPP #include #ifndef XYZZY_GLOBALS_EXTERN #define XYZZY_GLOBALS_EXTERN extern #endif XYZZY_GLOBALS_EXTERN A a; XYZZY_GLOBALS_EXTERN double x; #endif File2.cpp #include “globals.hpp” void g() { // Access a. // … } Leverage the preprocessor: $ gcc File1.cpp File2.cpp globals.cpp Isn’t this actually more complicated?

39 ODR, Revisited Let’s say you are the linker implementer. Could you make this work if you wanted to? [Show multiple_definitions] File1.cpp int a; void f() { // Access a. // … } File2.cpp int a; void g() { // Access a. // … } $ g++ File1.cpp File2.cpp...

40 What about this? We could even make this work, but which one? At some point, rules become too complicated. Sometimes simple rules are better, even if they sometimes seem to make things inconvenient. File1.cpp int a; void f() { // Access a. // … } File2.cpp int a = 1; void g() { // Access a. // … } $ g++ File1.cpp File2.cpp...

41 Include Guards The (loose) convention in C++ is to put each class in a separate header file. Is this correct? B.hpp class B { … }; D1.hpp #include "B.hpp" class D1 : public B { … }; D2.hpp #include "B.hpp" class D2 : public B { … }; main.cpp #include "D1.hpp" #include "D2.hpp" int main() { D1 d1; D2 d2; // … }

42 Include guards make includes “idempotent”. (This means it’s okay if a file gets included twice.) Maintains simple rule: If you use a class, include its header file. B.hpp #ifndef XYZZY_B_HPP #define XYZZY_B_HPP class B { … }; #endif D1.hpp #ifndef XYZZY_D1_HPP #define XYZZY_D1_HPP #include "B.hpp" class D1 : public B { … }; #endif D2.hpp #ifndef XYZZY_D2_HPP #define XYZZY_D2_HPP #include "B.hpp" class D2 : public B { … }; #endif main.cpp #include "D1.hpp" #include "D2.hpp" int main() { D1 d1; D2 d2; // … } Why the funny prefix?

43 Does this work? – // A.hpp #ifndef ACME_A_HPP #define ACME_A_HPP #include “B.hpp” struct A { B *b_field; }; #endif – // B.hpp #ifndef ACME_B_HPP #define ACME_B_HPP #include “A.hpp” struct B { A a_field; }; #endif

44 First-level of include: – // A.hpp #ifndef ACME_A_HPP #define ACME_A_HPP // B.hpp #ifndef ACME_B_HPP #define ACME_B_HPP #include “A.hpp” struct B { A a_field; }; #endif struct A { B *b_field; }; #endif Include of B.hpp from top- level A.hpp

45 Second-level of include – // A.hpp #ifndef ACME_A_HPP #define ACME_A_HPP // B.hpp #ifndef ACME_B_HPP #define ACME_B_HPP // A.hpp #ifndef ACME_A_HPP #define ACME_A_HPP #include “B.hpp” struct A { B *b_field; }; #endif struct B { A a_field; }; #endif struct A { B *b_field; }; #endif Include of B.hpp in top-level A.hpp Include of A.hpp in include of B.hpp in top- level A.hpp

46 Solution is a forward declaration to break the cycle. – // A.hpp #ifndef ACME_A_HPP #define ACME_A_HPP struct B; struct A { B *b_field; }; #endif – // B.hpp #ifndef ACME_B_HPP #define ACME_B_HPP #include “A.hpp” struct B { A a_field; }; #endif

47 How about this? – // A.hpp #ifndef A_HPP #define A_HPP struct B; struct A { B foo() { return B(); } }; #endif – // B.hpp #ifndef B_HPP #define B_HPP struct A; struct B { A foo() { return A(); } }; #endif Show recursive inline

48 Need to split apart class definition from function definition: – // A.hpp #ifndef MY_COMPONENT_HPP #define MY_COMPONENT_HPP struct B; struct A { inline B foo(); }; struct B { inline A foo(); }; inline B A::foo() { return B(); } inline A B::foo() { return A(); } #endif Show recursive inline

49 Can accomplish same effect by careful positioning. – // A.hpp #ifndef A_HPP #define A_HPP struct B; struct A { inline B foo(); }; #include “B.hpp” inline B A::foo() { return B(); } #endif – // B.hpp #ifndef B_HPP #define B_HPP struct A; struct B { inline A foo(); }; #include “A.hpp” inline A B::foo() { return A(); } #endif Show recursive inline

50 Header files should be independent. – // Should not need anything here. #include A header file should always be included in the implementation file. Which is better? – // File A.cpp #include #include // Code is here…

51 CLASSES

52 Objects What is an object? What is object-oriented programming? What is non-OOP? – In non-OOP, data and the code that use and modify data are all mixed together. There is not a clear notion that this code goes with this data. Data is “amorphous”, without clear groupings. Can you do object-oriented programming in C? – Xt – File systems – struct class1 { int (*method1)(struct class1 *, double x); double member1; int member2; }; p->method1(p, 3.14); Classes encapsulate operations and data, grouping them together. Class syntax is all about how to group the data and the operations, and what operations are valid, etc.

53 An object in C++ has a set of “fields”, known as data members. Those belong to the object. – Then there are a set of member functions, these operate on the data members.

54 Class Definition Class definition looks like: – class Foo { … } obj1, obj2; class Foo { … }; Foo obj1, obj2; Are these different types? – class Type1 { int mem1; double mem2; } o1; class Type2 { int mem1; double mem2; } o2; o1 = o2; // Type error? – Types in C++ are by name only, so above doesn’t work. How about this? typedef Type1 Type3; Type1 o1; Type3 o2; o1 = o2; // Type error? Typedefs are aliases, so it works.

55 Another kind of typing, not supported by C++, is “duck typing”. “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” – James Whitcomb Riley – If an object can behave like A, then it is an A. – Usually used with dynamic typing. Can add methods at run-time. – Just try to call the method. If it’s there, then it will succeed.

56 Member Variables Member variables (also known as data members or fields) are declared like: – class A { string _label; int m_position; double energy_, weight_; }; – Why all the funny stuff at the beginning or end?

57 Member Functions Member functions define the set of valid “operations” that you can do on an object of a particular class. – class A { public: void op1(int i); void op2(double x) { … } void op3(const std::string &); … }; void A::op1(int i) { … } void A::op3(const std::string &s) { … } (Normally the function definition and class definition would not be in the same file.) Member functions always operate on an object. – They have access to all member variables. – Remember, you cannot call a member function without an object! – (Except for static member functions, which we’ll talk about a bit later.)

58 Inside a member function, to refer to a member, just use the name: – class A { int member; … }; void A::func(int i) { int j = member*i; … } A a1, a2; a1.func(1); // Uses a1.member. a2.func(2); // Uses a2.member. What if a local variable has the same name as a member? – class A { int i, j; … }; void A::func(int i) { int ii = i; int j = 2; int k = j; … }

59 Inlined member functions – Implicitly class A { void f() { … } Java-style. – Explicitly class A { inline void f(); }; // Does this go in header file or.cpp file? inline void A::f() { … } – Why inline? What should be inlined? – [Show excessive_inlining.] – Don’t get in the habit of always defining the member function in the class, since it will cause excessive inlining.

60 Two (member) functions can have the same name. As long as they have different signatures, there is no conflict. – void foo(int); void foo(); void foo(int, int); int foo(int); // Okay?

61 The this Pointer Member functions execute “within” objects. In the member function, a special keyword is used to refer to the object within which the member function is executing. – class A { int member; void A::func(); }; void A::func() { // The type is as if defined as: // A *this; this->member; }

62 Inside a member function, class members are searched when a name is used. – class A { int a; … }; void A::func() { a = 1123; } This can be thought of an implicit usage of the this pointer, which can also be used explicitly for clarity or for disambiguation. – class A { int a; … }; void A::func() { int a; a = 123; this->a = 456; }

63 Static Class Members Suppose you want to assign a unique object ID to every instance of a class. How would you do it? – class A { int id; }; int obj_id; // Global counter. A::A() { id = obj_id++; } Disadvantages? – Global variables should be avoided. How else would you improve the above?

64 There is only one variable for each static member, which is used by all instances of a class. Using a static member can enforce better encapsulation, avoid polluting namespace, etc. – // In A.hpp. class A { private: const int id; static int next_id; }; – // In A.cpp. A::A() : id(next_id++) { } int A::next_id;

65 Const static integer members can be assigned a value in the class: – struct A { static const int N = 10; }; They can be used as compile time constants: – int array[A::N]; They do not require a definition unless there address is taken (odr-used).

66 Typedefs and Type Aliases Typedefs and type aliases can be defined in a class. – class A { public: typedef A *a_ptr; using b_ptr = B *; // C++11 … }; … A::a_ptr a; // Pointer to A. A::b_ptr b; // Pointer to B. – Type alias is the same as typedef except that with type alias can define alias templates. – In this case, it is not that powerful, but we will see later on that typedef s can be very useful, especially when combined with templates.

67 Member Access Control C++ provides a way to label members with different degrees of access from scopes outside of the class. – class A { int private_member; public: int public_member; private: int private_member2; }; – public: All have access. – private: Only member functions of the same class, or member functions of friend classes. – protected: Only member functions of the same class, friend classes, or derived classes have access.

68 What is a struct ? What is the difference between this class and this struct ? class A1 { public: void f(); int i1; private: int i2; }; struct A2 { public: void f(); int i1; private: int i2; };

69 A struct is the same as a class, except that initial access is public instead of private. class A1 { void f(); int i1; private: int i2; }; struct A2 { void f(); int i1; private: int i2; }; Private members Public members

70 Friends A function or operator can be granted access to private members. – class A { friend void foo(); private: int i; }; void foo() { A a; a.i; // Okay. } void goo() { A a; a.i; // Access violation. } Member functions and other classes can also be friends. – class A { friend int B::f(); friend class B; … };

71 A friend function can be defined in the friend declaration, and is implicitly inline: – struct A { friend void foo() { } }; A friend declaration is not actually a declaration: – struct B { friend void foo(); }; int main() { foo(); // Syntax error. } However, in some cases, argument-dependent lookup (ADL) will apply. – struct C { friend void foo(C *); }; int main() { C c; foo(&c); // Will compile, due to ADL. }

72 #include void f() { std::cout << "::f()\n"; } namespace N1 { struct A { friend void f() { std::cout << "N1::f()\n"; } friend void f(A *) { std::cout << “N1::f(A *)” << endl; } void h() { f(); f(this);} void g(); }; void A::g() { f(); f(this); } } int main() { N1::A a; a.h(); a.g(); } This always call the ::f(). N1::f() is not visible, except by ADL, and calling f() inside A does not cause ADL to kick in.

73 Is this breaking encapsulation? Is it how we think of encapsulation in the real world? – class Person { private: int private_info; … }; void Person::snoop(Person *other_person) { cout private_info private_info << endl; } This is arguably breaking encapsulation, but is syntactically okay. What if you strongly are against this? What can you do? – You can use conventions to try to enforce best practices. – Coding style is that only the same object can access private members. How Much Privacy Is There?

74 “Public” vs. public: I will sometimes use “public” in two different ways. – “You don’t want this to be part of your public API.” Don’t document it as something for external use. – “This member must have public: access for the code to work.” The first is a statement more at the design level. The second is at the implementation level. There is not always a perfect correspondence between the two levels.

75 What Do You Make Private? Which classes do you make friend classes? – class A { void somewhat_private(); void really_private(); void public(); }; – Suppose class B needs A::somewhat_private(), while class C needs A::really_private(). What do you do? In C++, a class has: – a “private” interface, composed of the data and function members exposed to friends and member functions. – A “public” interface, composed of public members, exposed to everyone else. In real life, how many “interfaces” do you, as a person, have? In the real world, our relationships are not divided into just public and private. – We have a completely public interface, – a professional interface used at work, – a friend interface used with friends, a family interface used with family, etc.

76 Similarly, an object might have more than just two “interfaces”. Suppose a class A had a helper class named Helper that needed access to a certain non-public interface, but not to all the private members of A. No way in current C++ to do this, but this is a possible syntax for it. – class Helper {…}; class A { expose_to Helper: void func1(); expose_to all: // Same as public: void func2(); private: void func3();

77 Forward Declarations Which of these are allowed? class A { int i; A *a; }; class A { int i; A a; }; class A { int i; static A a_member; }; class A { int i; B b; }; class B { int i; A a; }; class A { int i; B *bptr; }; class B { int i; A *aptr; }; –Will the above actually compile?

78 Use a forward declaration. – class B; class A { B *bptr; }; class B { A *aptr; };

79 Classes Define a Scope One of the scopes in C++ is class scope. – // Where can you use these names? class A { int i; void foo(); }; Outside of a class, can use resolution operator. – class A { … }; // This would refer to a member // of A. Will it compile? int i = A::var; – Remember that scope is about what a name refers to. You can refer to a name in a way that is a syntax error.

80 const Member Functions Objects (including primitives) in C++ can be declared const. – const A a, b; const int i = 2134; i = 1; // Okay? a = b; // Okay? a.my_method(); // Okay?

81 A member function can be called on a const object only if it does not change the object. C++ uses a keyword to indicate that the member function does not modify the object. What happens? – void A::func() const { member = 1234; } Which of these will compile? – void A::nonconst_func() { A *ap = this; } – void A::const_func() const { A *ap = this; } – void A::const_func2() const { const A *ap = this; } – void some_func(A *obj); // Changes obj. void A::func() const { some_func(this); }

82 Why do we need a keyword? Can’t the compiler just figure out whether or not the member function changes the object? – void A::func() { // Modifies member. this->member = 1234; } – void A::func() { // Just reads member. int i = this->member; } Hm......

83 Do these member function modify the object? – void A::func() { if (0 == 1) { this->member = 234; } } – void A::func() { if (the_two_millionth_digit_of_PI() == 3) { this->member = 234; } } Also, does the compiler always know the source code at the call site? – … a.func(); // What is the implementation of func()?... Just because a compiler can figure something out, should we let it? – Why do we need to define variables?

84 Let’s say that you really need to change a member in a const function. What do you do? Is this safe? – void A::func() const { A *ptr = const_cast (this); ptr->member = 1234; } – const A a_const; a_const.func(); // Okay? A a_nonconst; const A &const_ref(a_nonconst); const_ref.func(); // Okay? – [Show cast_away_const.] Rule says that casting away constness is okay, but if you try to cast something that was defined const, the behavior is undefined. If you cast away constness of something that was not defined const, but is being accessed through a const pointer or ref, then it is okay.

85 What does constness mean? – void func(const A &a) { const int i1 = a.member; some_other_func(); const int i2 = a.member; if (i1 != i2) { // Is this possible? … } } Constness does not mean that the object will not change. It means that you promise not to change it.

86 A const member function is guaranteed not to modify the object. Suppose you write a class named Trie, with a function: – int lookup(const std::string &) const; Your users are not quite satisfied with speed. You examine the usage patterns, and you notice that it looks like: – lookup “abcdef” … Repeated 1 million times. lookup “xyz” … Repeated 1 million times. etc. What might you do to improve performance?

87 Cache the last lookup: – class Trie { … std::string cached_key; int cached_value; }; int lookup(const std::string &key) const { if (key != cached_key) { cached_key = key; cache_value = real_lookup(key); } return cached_value; } Does this work? Should it work?

88 mutable keyword can be used to indicate that a member can be changed, even if the object is const. – class MyClass { mutable int var; }; Will allow this: – struct A { void func() const; mutable int a_member; }; void A::func() const { this->a_member = 234; } int main() { const A const_a; const_a.func(); }

89 Const-ness can be physical or logical. – Physical constness: the bits don’t change. – Logical constness: a user of the public interface of the object cannot detect any change. Which is better? – Often debated, but in my experience, I have found logical constness to be preferred, due to the issues in the previous slide. – I generally use logical constness.

90 Class Scope A number of things can be defined in class scope, and can be referenced from outside the class. – struct A { int data_member; void func_member(); typedef int typedef_member; class class_member { … }; static int static_data_member; static void static_func_member(); enum enum_member { … }; }; Nested types can be used normally: – A::typedef_member i; // Defines an int. // Defines an object of the nested class. A::class_member obj;

91 Name resolution needs to consider class scope. Local first, then class, then namespace.

92 Nested Classes Classes can be nested: – class A { class B { int i; void f(); }; void f(); int i; }; Okay, but what does it mean?

93 Suppose we create an object of type A. Is this the correct picture of the object? – No, nesting a class only nests the scopes created by the classes. A a; Object of class of A::B class A { class B {…}; … };

94 There is no nesting of objects implied. A nested class can be used to create objects external to the outer class. A a_obj; class A { public: class B {…}; … }; A::B b_obj1; A::B b_obj2;

95 How can one get this, if this is what one wants? – Use composition. – Or use inheritance. Object of class A Object of class of A::B class A { class B {…}; B b; };

96 But this can be done without nested classes. What is the purpose then of nested classes? – The scoping helps to hide information, and also reduce name clashes. – With overloading, exceptions, and templates, often useful to create small helper classes, that are only used inside the outer class. These make sense to define as nested classes. Object of class A Object of class of B class B {…}; class A { B b; … };

97 What about access and nested classes? Consider: – class A { class B { int B_priv; void B_f(); }; void A_f(); int A_priv; }; void A::A_f() { B b; b.B_priv; // Allowed? } void A::B::B_f() { A a; a.A_priv; // Allowed? } A nested class is automatically a friend of the outer class. – I.e., inner can access outer. The outer class is not a friend of the inner class, however. – I.e., outer cannot access inner.

98 Local Classes Can be declared in a function body. – void f() { class Local {…}; … } Everything must be in class definition. Sometimes handy for creating small, local functions.

99 Can call recursively, and access local static variables. – void work() { static int i; struct Local { static void foo() { goo(i + 1); } static void goo(int j) {... } }; Local::foo(); }

100 INITIALIZATION, ASSIGNMENT, AND DESTRUCTION

101 Default vs. Implicit For some things, the compiler will automatically generate one for you, if you don’t define one. These are known as the implicit versions. What are some of these? – Default constructor – Destructor – Copy constructor – Copy assignment operator A constructor that takes no arguments is called the default constructor.

102 Objects are initialized with constructors: – class A { public: A(); // Default constructor. A(int); A(double, int, const B &); }; What get’s executed? – class A { public: A() { … } // Default ctor. A &operator=(const char *) { … } // Copy assign. }; – A a = “hello”; These are essentially the same: – A a(“hello”); // Direct initalization. A a = “hello”; // Copy initialization, NOT assignment. – [Show equal_ctor.] Constructors

103 Default constructor is used when no constructor arguments are given. – A a1, a2(3), a3(); – What is the difference between a1 and a3 ? Hint: A a4(int); Default arguments can be useful: – Time::Time(int hour, int min, Timezone tz = UTC);

104 Which of these is okay? – class A { public: A(int); }; class B { }; B b; // Compiles? A a; // Compiles? – If you don’t define any constructor, the compiler will implicitly define a default constructor. – If you define a non-default constructor, then the compiler will not implicitly define the default constructor.

105 You can explicitly ask the compiler to generate the default constructor in C++11: – struct Foo { Foo() = default; // Inlined. std::string str; }; – struct Foo { Foo(); std::string str; }; // In.cpp file. Foo::Foo() = default; // Not inlined. What happens if you don’t do the above? Any difference? What about this? – struct Foo { Foo() = default; Foo(const char *s) : str(s) {} std::string str; };

106 Conversions How would you critique this code? – struct String { // Construct using given C string. String(const char *s) {... } // Create a string of spaces of the given length. String(int length_) {... } int length; char *buf; }; void print(const String &) { cout << s.buf << endl; }... int nl = 100; // Name length, used later. // Create three names. String n1(“alice”), n2(“bob”), n3(“joe”); print(nl); // Print the first name.

107 – struct Polygon { Polygon(int n_sides);... }; void draw(const Polygon &);... Polygon square(4); int squared = 4*4; // Area of the square. // Draw the square created above. draw(squared);

108 The programmer most likely did not intend the automatic conversion. – How to prevent it? Constructors define conversions. What if you don’t want the conversion? – Disable with explicit keyword. – For example, explicit Polygon(int n); – class String { public: // Create a string of spaces // of the given length. explicit String(int length); … }; Explicit constructors also cannot be used in copy initialization: – Polygon p1(10); // Okay. Polygon p2 = 10; // Error if explicit.

109 Explicit Temporaries Let’s say you have a 2-D Vector class: – Vector v1(x1, y1), v2(x2, y2); v1 = v2; v2 =...; // How to assign (2.3, 3.1) to v2? Could use a “setter” method. – v2.set(2.3, 3.1); The more idiomatic C++ way is with explicit temporary. – v2 = Vector(2.3, 3.1); Also very commonly used with return values. – Vector operator+(const Vector &v1, const Vector &v2) { return Vector(v1.x + v2.x, v1.y + v2.y); }

110 Member Initialization Consider a class designed to be a better string: – class String { … int len; // Length of the string char *buf; // Array of chars to hold it. }; What should the initial values be, when we create a string? How do the members get the initial values? [Show string_init.]

111 Initialize to nullptr is one possibility: – class String { String() : len(-1), buf(nullptr) {} String(const char *s) : buf(strdup(s)) {} ~String() { free(buf); } int len; char *buf; }; – String operator+(const String &s1, const String &s2) { if (s1.buf == nullptr) { return String

112 Consider: – struct A {…}; struct B { B(); A a; }; B::B() { // How do we initialize the a member? } If we do nothing, then the default constructor for A will be used, if there is one. If default constructor for A is not right, then use constructor initializer list: – B::B() : a(12, 3) {}

113 Any difference between the two versions of the constructor? – class A { public: A(const char *name); private: std::string name_; }; // Version 1. A::A(const char *name) { name_ = name; } // Version 2. A::A(const char *name) : name_(name) {}

114 Any time when you must use initializer list syntax? – struct B { B(int); }; class A { public: A(const char *); private: const std::string name_; B b; }; A::A(const char *name) : b(1) { name_ = name; // Okay? }

115 Construction of const object Is this okay? – struct A { A() { member = 1234; // Okay? } int member; }; // Assigns to member inside ctor. const A a; Inside the constructor of a const object, the this pointer is not const, so we can assign to members. Makes sense in hindsight, since this must be statically typed.

116 Member Initializers Does this work? – class A { int position = 2; }; – No in C++98, yes in C++11. Also can do: class B { vector v = {1, 2, 3}; vector v2{4, 5, 6}; };

117 Any advantage? Gives a default that all constructors use. – class A { A(int i) {} A() = default; int position = 2; };

118 Constraining Object Creation What if we don’t want to allow an object of a particular class to be created just anywhere? – class A {…}; void foo() { A a; // How to disallow this? } Use private, unimplemented constructor (C++98): – class A { private: A(); }; How is the object ever created then? – Can be created in friends, static member functions, etc.

119 Note that if you define a private, non-default ctor, the default ctor will not be generated: – class A { private: A(int); }; In C++11, you can make this explicit with the delete keyword. – class A { A() = delete; private: A(int); };

120 Copy Constructors Consider the following: – void foo(A a_param) { … } A a_arg(2); foo(a_arg); – Is a_param the same object as a_arg ? If not, then how is it initialized? What function is called? Initialization of an object with another object is done so often it has a special name: copy construction. – The prototype is: A(const A &).

121 If you don’t define a copy constructor, one will be automatically defined (implicit), that has the following definition. – class A { B1 b1; B2 b2; int i; }; A::A(const A &a) : b1(a.b1), b2(a.b2), i(a.i) {}

122 Consider a string class. – class String { public: String(); ~String(); private: char *buf; }; String::String() : buf(malloc(10)) { strcpy(buf, “hello”); } String::~String() { free(buf); } Okay? – Does the implicit copy constructor do the right thing for this class?

123 If the implicit copy constructor is not correct, to disallow copy construction, use a private, undefined copy constructor. – class A { private: A(const A &); // Not defined. … }; In C++11, use delete keyword. – class A { A(const A &) = delete; … };

124 Delegating Constructors Let’s say you have a class that needs to be initialized with a string and an integer. – A a(“hello”, 5); – struct A { A(const std::string &s, int i) { /* … */ } // … }; You would like to make the integer default to 1 if not supplied. – A a(“hello”); – struct A { A(const std::string &s, int i = 1) { /* … */ } // … }; Also, you’d like to make the string default to “hello” if not supplied. – A a(5); – struct A { A(const std::string &s = “hello”, int i) { /* … */ } // … }; A(const std::string &s = “hello”, int i) { /* … */ } A(int i) { … }

125 You could also use a constructor helper: – struct A { A(int i) { ctor_helper(“hello”, i); } A(const std::string &s, int i = 1) { ctor_helper(s, i); } private: void ctor_helper(const std::string &, int i); // … }; Members are constructed, then assigned to, which is inefficient. Doesn’t work if there are const members. – struct A { A(int i) : count(i) { ctor_helper(“hello”, i); } private: void ctor_helper(const std::string &, int i); const std::string s; const int count; // … };

126 No great solution in C++98. In C++11, use delegating ctors: – struct A { A(const std::string &n, int c) : name(n), count(c) { /* … */ } A(int c) : A(“hello”, c) { /* … */ } A(const std::string &n) : A(n, 1) { /* … */ } private: const std::string s; const int count; // … };

127 Destructors Is this correct? – struct A { A(); char *buf; }; A::A() : buf(malloc(10)) {} Memory leak, to fix: – struct A { A(); ~A(); char *buf; }; A::A() : buf(malloc(10)) {} A::~A() { free(buf); buf = 0; } Necessary?

128 Clean up when an object goes out of scope. – What kind of things might it do?

129 Assignment (Copy) Assignment operator is called: – class A {…}; A a, b; a = b; If no (copy) assignment operator is defined explicitly, an implicit one will be defined by the compiler. It will be equivalent to: – class A { B b, c; int i; }; A &A::operator=(const A &a) { b = a.b; c = a.c; i = a.i; return *this; }

130 Consider our string class again. – class String { public: String(const char *s); ~String(); private: char *buf; int len; // Length not including null byte. }; String(const char *s) : len(strlen(s)) { buf = new char[len + 1]; strcpy(buf, s); } ~String() { delete [] buf; } Would the implicit assignment operator be correct for this? To disallow, make it private and undefined. Or use delete keyword.

131 What should the return type of the assignment operator be? – ??? MyType::operator=(const MyType &); – Should this work? a = b = c; // Which way does this group? a = (b = c); // Can it return a value? – For efficiency, it should return a reference. Can it be a const reference? What about this? – void f(MyType &); f(a = b); // Should this work?

132 Value Return of Classes What gets executed here? – class A { public: A(int); }; class B { public: B(const A &); }; A f() { return 1; } B b(f()); Semantics same as initialization.

133 Aggregate class Literal class Literal types

134 Aggregates Arrays and certain classes are called aggregates. These capture some of the properties of C struct s. An aggregate class has: – No user-provided constructors. – No in-class initializers for non-static data members. – No private or protected non-static data members. – No base classes. – No virtual functions.

135 Initializer Lists Initializer lists: – // An aggregate. struct A { int i; const char *s; }; A a1 = {1, “hello”}, a2{2, “goodbye”}; // Not an aggregate. struct B { int i; private: const char *s; }; B b{1, “hello”}; // Compile-time error. // Not an aggregate, but has a ctor. struct C { C(int i_, const char *s_) : i(i_), s(s_) {} private: int i; const char *s; }; C c{1, “hello”}; // Okay.

136 In many situations, the compiler will turn an initializer list into a std::initializer_list. – // Uses std::initializer_list. struct D { D(int, int); // C1 D(int, double); // C2 D(const std::initializer_list &il); // C3 … }; D d{1, 2, 3}; D d2{1, 2}; // Prefers initializer_list ctor. D d3{1, 2.0}; // Calls C2. D d4{1, 2.0, 3}; // Error.

137 Trivially Copyable No non-trivial copy/move ctor. A copy/move ctor is trivial if: – Not user-provided. – Class has no virtual functions and no virtual base classes. – Ctor selected to copy/move each direct base class subobject is trivial. – Each non-static data member is copied/moved using trivial ctor. No non-trivial copy/move assignment operators. A copy/move assignment operator is trivial if: – Not user-provided. – Class has no virtual functions and no virtual base classes. – Assignment operator selected to copy/move each direct base class subobject is trivial. – Each non-static data member is copied/moved using trivial assignment operator. Has a trivial destructor. A destructor is trivial if: – Not user provided. – Not virtual. – All direct base classes have trivial destructors. – All non-static data members have trivial destructors.

138 Trivial Class A class is trivial if it is trivially copyable and it has a trivial default constructor. Trivial default constructor: – Not user provided. – Class has no virtual functions or virtual base classes. – No non-static data member has brace-or-equal- initializer. – All direct base classes have trivial default constructors. – All non-static data members have trivial default constructors.

139 Standard Layout Class When is a class/struct compatible with C? Standard layout class: – Has no non-static data members of type non-standard-layout class (or array of such types) or references. – Has no virtual functions and no virtual base classes. – Has the same access control for all non-static data members. – Has no non-standard-layout base classes. – Either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members. – Has no base classes of the same type as the first non-static data member.

140 POD Class POD means “plain, old data”. Both trivial and standard-layout and has no non-static data members that are not POD.

141 Aggregate Class Trivially copyable TrivialStandard Layout User-provided ctors X Brace-or-equal- initializers for non-static data members X Non-public, non-static data members X Base classesX Virtual functions X

142 OPERATORS AND CONVERSIONS

143 Overloading Operators can also be overloaded. – Complex c1(…), c2(…), c3; c3 = c1 + c2; There are complicated rules for figuring out which overloaded function to call. Why overload? – Sometimes a particular operation, like finding the maximum of two numbers, can have different implementations depending on the actual types.

144 Operators Consider these operators defined in the context of two classes: – class Point { private: double x, y; }; class Vector { private: double x, y; }; These classes have exactly the same data members. Is there any point in having two classes? Why not just make them the same? – class Pair { private: double x, y; };

145 Does this code do what the author intended? – Pair s1p(…); // Position of starship 1. Pair s1v(…); // Velocity of starship 1. double dt = …; // Elapsed time. // Update starship position, assuming // that dt seconds have passed since the // last update. s1p = s1p + dt*s1p; If the author had used separate classes for points and vectors, would it have made any difference?

146 Equality ( == ) Equality – inline bool operator==(const Point &p1, const Point &p2) { return p1.x == p2.x && p1.y == p2.y; }

147 Inequality ( != ) Inequality: – inline bool operator!=(const Point &p1, const Point &p2) { return !(p1 == p2); }

148 Addition ( + ) Point + point? – Ill-defined. Point + double? – Ill-defined. Point + vector? – Point operator+(const Point &p, const Vector &v) { return Point(p.x + v.x, p.y + v.y); } Vector + point? – inline Point operator+(const Vector &v, const Point &p) { return p + v; }

149 Multiplication ( * ) Point*point? – Ill-defined. Point*double? – Ill-defined. double*vector? – inline Vector operator*(const double s, const Vector &v) { return Vector(s*v.x, s*v.y); } vector*double? – inline Vector operator*(const Vector &v, const double s) { return s*v; } vector*vector? What do we do about cross-product? – Can we just “borrow” some other operator to use for cross product, such as && ? – Vector &operator&&(const Vector &v1, const Vector &v2);

150 Full declaration Code is: – class Vector; class Point; Point operator+(const Point &, const Vector &); class Vector { friend Point operator+(const Point &, const Vector &); … }; class Point { friend Point operator+(const Point &, const Vector &); … };

151 Index operator ( [] ) Index – class DynamicArray { public: double &operator[](size_t i); double operator[](size_t i) const; private: double *const data; const size_t length; }; double & DynamicArray::operator[](size_t i) { return data[i]; }

152 Function call ( () ) Functor: Object that behaves like a function. – class Compare { public: bool operator()(int i, int j) { return i < j; } }; Compare cmp; if (cmp(1, 2)) { … } // If <. In C++, use functors (with virtual functions if needed) where you would normally use function pointers.

153 Also can do double-duty as a multi- dimensional index operator: – class Array2 { public: double &operator()(int i, int j) { return data[???]; } private: size_t n_cols; double *data; }; – return data[n_cols*i + j];

154 Member Access and Dereference ( -> and * ) These are somewhat special. They allow a class to behave like a pointer. Is there a way to solve memory leak problems like below by using objects? – { MyClass *ptr = new MyClass; ptr->my_method(); // Oops, memory leak. }

155 Use a “smart pointer”: – class MyClassPtr { public: MyClassPtr(MyClass *p) : ptr(p) {} ~MyClassPtr() { delete ptr; ptr = 0; } MyClass *operator->() { return ptr; } MyClass &operator*() { return *ptr; } private: MyClass *ptr; }; { MyClassPtr sp(new MyClass); sp->my_method(); (*sp).my_method(); // What happens here? } This is not a robust version, just for example. It is similar std::auto_ptr.

156 If the member access returns an object type, it will recurse: – struct A { int field1; }; struct B { A *operator->() { return &a; } A a; }; struct C { B operator->() { return B(); } };... C c_obj =...; c_obj->field1; – (C_obj.operator->().operator->())->field1;

157 Left and Right Shift ( > ) These are used primarily for output operators: – void operator<<(ostream &os, const Point &p) { os << “(“ << p.x << “, “ << p.y << “, “ << p.z << “)”; } Given the above, will this work? – Point p1(…), p2(…); cout << p1 << p2 << endl;

158 Assignments ( *= ) How do we make this work? – Vector v(…); double s = …; v *= s; // What does this do, mathematically? – Vector &operator*=(double s) { this->x *= s; this->y *= s; return *this; }

159 Increment ( ++ ) and Decrement ( -- ) Operators What is the value of i in these cases? – int j = 3; int i = ++j; – int j = 3; int i = j++; The postfix and prefix operators are distinguished with a hack. – operator++(int); // Postfix operator++(); // Prefix

160 How would you implement 128-bit unsigned integers? – Int128 i, j1(1), j2(1); i = j1++; // What should the value of i be? i = ++j2; // What should the value of i be? – class Int128 { public: Int128(uint64_t h = 0, uint64_t l = 0) : m_high(h), m_low(l) {} ??? operator++() { // Prefix if (++m_low == 0) { m_high++; } return ???; } ??? operator++(int) { // Postfix if (++m_low == 0) { m_high++; } return ???; } private: uint64_t m_high, m_low; };

161 – class Int128 { public: Int128(uint64_t h = 0, uint64_t l = 0) : m_high(h), m_low(l) {} inline Int128 &operator++(); // Prefix inline Int128 operator++(int); // Postfix private: uint64_t m_high, m_low; }; inline Int128 & Int128::operator++() { //Prefix if (++m_low == 0) { m_high++; } return *this; } inline Int128 Int128::operator++(int) { // Postfix uint64_t org_high = m_high, org_low = m_low; this->operator++(); return Int128(org_high, org_low); }

162 – Int128 &Int128::operator++() { //Prefix if (++m_low == 0) { m_high++; } return *this; } Int128 Int128::operator++(int) { // Postfix uint64_t org_high = m_high, org_low = m_low; this->operator++(); return Int128(org_high, org_low); } Which is more efficient? How many temporaries are created? – Int128 i, j1(1), j2(1); i = j1++; // What should the value of i be? i = ++j2; // What should the value of i be?

163 User-Defined Conversions Suppose we have our Int128 class. – class Int128 { … }; We’d like to use some function with this prototype: – void foo(Int128 &); Can we do this? –... foo(1234); Yes, since there is a constructor: – Int128::Int128(uint64_t h = 0, uint64_t l = 0);

164 So, like this, right? – void foo(Int128 &); … foo(1234); Hm…what happens here? – void foo(Int128 &i) {... i = j; }... foo(1234); Must be const or rvalue reference. – void foo(const Int128 &);... foo(1234); – void foo(Int128 &&); … foo(5678);

165 So we defined a conversion from int to Int128. Can we go the other way? – void foo2(int); Int128 i;... foo2(i); Yes. – class Int128 { public: operator int() const;... }; Int128::operator int() const {... // Convert to int. return result; }

166 Any conversion is possible. – class A { public: const operator *my_struct(); operator double(); private: my_struct a_struct; }; const A::operator *my_struct() { this->a_struct.field1 = 1.234; this->a_struct.field2 = 4.567; return &this->a_struct; } A::operator double() { return 3.14; } – A a(…); void f1(double); void f2(const mystruct *); f1(a); f2(a);

167 To force the use of a cast, use the explicit keyword. – class A { public: explicit const operator *my_struct(); operator double(); private: my_struct a_struct; }; – A a(…); void f1(double); void f2(const mystruct *); f1(a); f2(a); // Error. f2(static_cast (a)); // OK.

168 Especially important with a bool conversion. – struct A { operator bool() {... }... };... A a; int i = a; // Unintended, but compiles and runs.... struct B { explicit operator bool() {... }... }; int j = b; // Gives compile-time error.... if (a) {... } // Works. // Also works, because it’s a boolean context. if (b) {... } Conversion is still implicit if in boolean context. Replaces the “safe bool idiom” in C++98.

169 Member or friend? Member or (friend/non-friend) free? – Vector v1, v2; v1 = v2*s; – Vector operator*(const Vector &, double); – Vector Vector::operator*(double) const; – v1 = s*v2; // ? Consider a complex number example. – class Complex { Complex(double real, double img = 0); Complex operator*(const Complex &);... }; Complex c1 = 4*c2; // Syntax error. – Complex operator*(const Complex &, const Complex &); class Complex { Complex(double real, double img = 0);... }; Complex c1 = 4*c2; // OK.

170 Temporaries Consider the addition operator for vectors: – Vector operator+(const Vector &v1, const Vector &v2) { return Vector(v1.x + v2.x, v1.y + v2.y); } In the expression below, how many temporaries are generated? – v = v1 + v2 + v3; Any solution? – Not in C++98, but move semantics in C++11 can help.

171 What is the lifetime of a temporary? – struct A { A(int); void method(); }; void foo1(const A &); A foo2(); foo1(1); // A ref is passed to foo(). foo2().method(); // Call a method on temp? – const A &ar(foo2()); ar.method(); // Okay??

172 Header Files for Classes Conventional practice: – Header files do not have an explicit dependencies. #include // Not allowed #include – Header files are idempotent. #include #include // Okay. If this conventional practice is followed, does order matter? – #include #include – Versus? #include #include

173 Suppose you have a class A. – Header file in A.hpp. – Implementation file in A.cpp. In your A.cpp, where should you include A.hpp ? – #include … // Some include file. #include … // Some other include file. #include … // Some other include file. #include “A.hpp” – #include “A.hpp” #include … // Some include file. #include … // Some other include file. #include … // Some other include file.

174 Summary Cannot be overloaded: – ?: (conditional) –. (member selection) –.* (member selection with pointer-to-member) – :: (scope resolution) – sizeof (object size information) – typeid (object type information) – Cast operators: (type), static_cast, dynamic_cast, reinterpret_cast, const_cast Must be member function: – = (assignment) – () (function call) – [] (subscripting) – -> (member access)

175 If something already has a clearly defined meaning, then you can’t overload it. – int operator&&(int, int); // Okay? – int operator&&(MyClass a, int); // Okay? – int operator&&(MyClass *ap, int); // Okay? – int operator&&(MyClass &a, int); // Okay? – enum Foo { RED, GREEN, BLUE }; int operator&&(Foo, int); // Okay?

176 Special Values Suppose you had a smart pointer class. How would you check it for being null? Suppose you had a time class. How would you get the current time? [Show special_ values]

177 Comparison against zero could use a regular object with zero value: – class Time { static Time zero; }; if (t == Time::zero) {…} Or it could use a tag struct. In this case, any object of the type means zero. – class ZeroTime {} zero_time; if (t == zero_time) {... } Or could overload comparison to int: – if (t == 0) {... } But in this case it would still be called, even if it was 1234 instead of 0. Can get now time by a static function. – Time t = Time::now(); Or can create a set-to-now member function: – t.setToNow();

178 INHERITANCE

179 Inheritance A class may be derived from (inherit from) another class. The class that is derived from is the base class. – Which is more general, the base class or the derived class? – Why inherit? What do we gain by adding inheritance to a language? What would we lose if we took it out? Main thing is layered abstraction. Consider a hierarchy of animals, including felines, canines, and mammals. Code that doesn’t care if it is a dog or cat can deal with just mammals. Inheritance defines what we call the Is-A relationship. Mammal CatDog

180 Open-Closed Principle Software should be open for extension, closed to modification. – Hard to accomplish in practice.

181 Liskov Substitution Principle (LSP) If D is a subtype of B, - then objects of type B can be replaced everywhere with objects of type D, - without impacting any of the desired properties of the program. In other words, – if D derives from B, you should be able to replace objects of type B everywhere with objects of type D, and nothing will “go wrong”.

182 So using derived type object should still work. – void do_something(B *); B b; do_something(&b); D d; // D derives from B. do_something(&d);

183 A rectangle has four lines, each angle is 90 degrees. A square has four lines, each of the same length. – Each angle is 90 degrees. Is a square a rectangle? Then to model this, we should derive square from rectangle: – class Square : public Rectangle { // … }; Should this work? – Rectangle rect; Square sq; void do_something(Rectangle *r); do_something(&rect); do_something(&sq);

184 Consider: – class Rectangle { public: void setWidth(double x); void setHeight(double y); //... }; – void do_something(Rectangle *r) { r->setWidth(10); r->setHeight(5); //... } Rectangle rect; do_something(&rect); – class Square : public Rectangle { /*... */ }; Square sq; do_something(&sq);

185 Ways to resolve: – Changing either width or height of a square changes the other. – A Square object is not a Rectangle object. – Don’t use mutators. (Use a FP style.) – Allow object to change type.

186 Flat or Deep? Should a checking account and a savings account use separate classes or the same classes? – Checking is positive fee, zero interest. – Savings is zero fee, non-negative interest. Student and staff? Generally flat is preferred.

187 Defining the Hierarchy To inherit: – class B { // Accessible to derived classes. protected: int i; private: int j; }; class A : public B { … }; void A::some_func() { i; // Allowed. j; // Error. }

188 To prevent inheritance, use final keyword (C++11). – class A final { /* … */ }; class B : public A {// Syntax error. /* … */ }; Can also have protected and private inheritance. – class Derived : protected Base { /* … */ }; – class Derived : private Base { /* … */ };

189 Sub-objects An instance of derived class contains the members from the base class as what we call subobjects. – class A {…}; class B : public A {…}; class C : public B {…}; A part B part C part

190 Inheriting A derived class can access data members in base classes, if given protected access. A member function defined in a base class is automatically inherited by the derived class. – class Base { public: void func(); }; class Derived : public Base {}; Derived d; d.func(); // Calls Base::func().

191 Consider: – class B { public: void func(); }; class A : public B { public: void func(); }; A a; a.func(); // Calls which? A function that is defined in the derived class hides the same function defined in the base class. How to call the B version? – // Use resolution operator to call base class. a.B::func(); Hiding

192 Which ones are called? – struct Base { void func(double); void func(int); }; struct Derived : public Base { void func(int); }; Derived d; d.func(1234); // Which does this call? d.func(12.34); // Which does this call?

193 Which ones are called? – struct Base { void func(double); void func(int); }; struct Derived : public Base { void func(int); private: void func(double); }; Derived d; d.func(12.34); // Which does this call?

194 Normally, there is no overloading of hidden names. Can get this via “using”. – struct Base { void func(double); void func(int); void func(const char *); }; struct Derived : public Base { using Base::func; void func(int); private: void func(const char *); }; Derived d; d.func(1234); // Which does this call? d.func(1.23); // Which does this call? d.func(“hello”); Note derived class still gets precedence if declared in both.

195 [Show using_overloading.] This code compiles on g++, gives ambiguity error on clang++: – #include struct B { void func(double) { std::cout << "B::func(double)" << std::endl; } void func(int) { std::cout << "B::func(int)" << std::endl; } }; struct D1 : public B { void func(double) { std::cout << "D1::func(double)" << std::endl; } }; struct D2 : public D1 { using B::func; using D1::func; void func(int) { std::cout << "D2::func(int)" << std::endl; } }; int main() { D2 d2; d2.func(1); d2.func(1.0); }

196 All base overloads must be accessible to derived class. – struct Base { void func(double); protected: void func(); private: void func(int); }; struct Derived : public Base { using Base::func; void func(int); };

197 Access is determined by the point at which the using declaration occurs: – struct Base { void func(double); protected: void func(); }; struct Derived : public Base { private: using Base::func; public: void func(int); }; derived.func(1.1); // Compile-time error.

198 Construction A derived object has a sub-object that is a instance of the base class. – When does the sub-object constructed? Which should be constructed first? Generally speaking, it makes more sense to construct the base class first. – class Base { protected: Base(); }; class Derived : public Base { public: Derived(); }; Derived d;

199 Consider: – class Base { protected: Base(int); }; class Derived : public Base { public: Derived() { … } }; Will it compile?

200 Calling constructor of base classes. – If we wish to call a non-default constructor, use a constructor initialization list: – class B { public: B(int); }; class Derived : public B { public: Derived(); private: B b; }; Derived::Derived() : B(123), b(456) {}

201 – struct A { A(int, int); A(const char *); }; struct B : public A { B(); A a; }; B::B() : A(1, 2), a(“a”) {…}

202 Inheriting Constructors (C++11) Constructors can be inherited in C++11. – struct Base { Base(int); }; struct Derived : public Base { using Base::Base; }; Derived d(1);

203 Destructors Destructors of base classes are called. What order should destructors be called? – class Base { public: ~Base(); }; class Derived : public Base { public: ~Derived(); };

204 Polymorphism What does the word literally mean? What does it mean in terms of C++?

205 Virtual Functions A virtual function is one that when you call it through a pointer or a reference to a base class, calls the implementation in the most derived class. – class Base { public: virtual void foo() { printf(“Base\n”); } }; class Derived : public Base { public: virtual void foo() { printf(“Derived\n”); } }; Derived d; Base b; Base &br_d(d), &br_b(b), *bp = 0; bp = &b; bp->foo(); bp = &d; bp->foo(); br_d.foo(); br_b.foo();

206 Do we need the virtual in the derived class? – class Base { public: virtual void foo1(); void foo2(); }; class Derived : public Base { public: /* virtual */ void foo1(); void foo2(); }

207 Which functions get called? – class A { public: void foo(); }; class B : public A { public: virtual void foo(); }; class C : public B { public: virtual void foo(); }; C c; A *ap = &c; B *bp = &c; ap->foo(); bp->foo(); bp->A::foo(); c.B::foo();

208 What happens here? – class Base { public: virtual void foo(); }; class Derived : public Base { private: void foo(); }; Derived d; Base &br(d); br.foo(); As a thought experiment, let’s say that we wanted to disallow this. Is this practical/wise?

209 Not all overloads of a function must be virtual: – class Base { public: virtual void foo(int); void foo(double); void foo(const char *); }; class Derived : public Base { public: void foo(int); void foo(double); void foo(); }; Derived d; Base &br(d); br.foo(1); br.foo(1.1); br.foo(“hello”); br.foo(); d.foo(1); d.foo(1.1); d.foo(); d.foo(“hello”); Such code is unlikely to be a good idea, but it may happen unintentionally.

210 Virtual and using declaration using declarations still result in dynamic dispatch. – struct Base { virtual void func(double); }; struct Derived1 : public Base { private: virtual void func(double); }; struct Derived2 : public Derived1 { void func(int); }; int main() { Derived2 d2; d2.func(1.0); } using Base::func; using Derived1::func;

211 Operators Can Be Virtual Recall that operators are just functions. So they can be virtual: – struct Log { virtual Log &operator<<(const char *); }; struct RemoteLog : public Log { virtual Log &operator<<(const char *) override; }; void emergency(Log &l) { l << “Computer on fire!”; }

212 Forcing/Preventing Overriding (C++11) To flag an error when you intend to override, but actually aren’t, use the override keyword. – struct Base { virtual void foo(int); }; struct Derived : public Base { virtual void foo(double) override; }; – Without override, the above would compile. To prevent overriding, use the final keyword. – struct Base { virtual void foo(int) final; void goo() final; }; struct Derived : public Base { virtual void foo(int); // Syntax error. void goo(); // Syntax error. };

213 Virtual Destructors Will this do the right thing? – Base *b = new Derived; delete b; To cause the destructor for the derived class to be called, use a virtual destructor: – class Base { public: virtual ~Base() {} }; You almost always want a virtual destructor if you have a polymorphic class.

214 Default Arguments What default arguments will be used? – class Base { public: virtual void foo(int i = 0); }; class Derived : public Base { public: virtual void foo(int i = 1); }; Derived d; Base *b = &d; b->foo(); // Will this pass one or zero?

215 Parameter-Based Virtual Dispatch Which output operator does this call? – class Base { public: virtual ~Base(); … }; ostream &operator<<(ostream &os, const Base &) { // Output for Base class. } class D : public Base { … }; ostream &operator<<(ostream &os, const D &) { // Output for D class. } D d; Base b, &br_d(d); cout << b; // Which does this call? cout << d; // Which does this call? cout << br_d; // Which does this call?

216 Problem is that C++ does virtual dispatch only on the object type of the member function, not on any parameters. Solution? – [param_dispatch/] – Turn it into a member function call.

217 Redirected dispatch. – ostream &operator<<(ostream &os, const Base &b) { b.print(os); return os; } class Base { virtual void print(ostream &os); … }; class D : public Base { virtual void print(ostream &os); … }; D d; B b, &br_d(d); cout << b; // Which does this call? cout << br_d; // Which does this call?

218 Ctor Double-Dispatch Suppose you want to do something like this: – class Base { … }; class D1 : public Base {… }; // Polymorphic. class D2 : public Base {… }; // Polymorphic. class A { A(const D1 &); A(const D2 &); }; D1 d1; Base &b1(d1); A a(b1); // Which ctor does this call? Solution?

219 No great solution. Can do it like this: – class Base { virtual void makeA(A *) const = 0; }; class D1 : public Base { void makeA(A *a) { a->ctor(*this); }; class D2 : public Base { void makeA(A *a) { a->ctor(*this); }; class A { A(const Base &) { b->makeA(this); } // Do these need to be virtual? void ctor(const D1 &); void ctor(const D2 &); }; D1 d1; Base &b1(d1); A a(b1);

220 Constructors and Virtual Functions What does this call? – class Base { Base(); virtual void helper(); }; class Derived : public Base { virtual void helper(); }; Base::Base() { // Does this call Derived::helper(), or // Base::helper()? this->helper(); … } – Hint: At the point of call, has the constructor for Derived been called yet? – Is it safe to call a method on an object that has not been constructed?

221 Pure Virtual Functions A base class can indicate that the class of any instantiated object must override the function. – struct Base { virtual void f() = 0; }; struct D1 : public Base { … }; struct D2 : public D1 { virtual void f(); } struct D3 : public D2 { … }; Base b; // Okay? D1 d1; // Okay? D2 d2; // Okay? D3 d3; // Okay? Called an abstract class.

222 Is this allowed? What does it mean? Could the implementation ever be called? – struct Base { virtual void f() = 0; }; // An implementation of a pure virtual function. void Base::f() {…} Used to provide helper functions. – void Derived::f() { // Call base class version first. this->Base::f(); … } Note that calling PVF from base is undefined behavior. – Base::Base() { f(); // Tries to calls Base::f() during construction. }

223 Can you have a pure virtual destructor? What does it mean? Why? – class Base { public: // Can I do this? virtual ~Base() = 0; }; // Can I do this? Base::~Base() { … }

224 Summary: – A pure virtual function does NOT mean that you didn’t define it. – But you can never instantiate an class that does not have all PVFs defined.

225 Cloning If you have a pointer to a derived type, it is easy to make a copy of it: – D *copy_of_d = new D(*d); What if you only have a base class pointer? – B *bp = …; // Might point to a D. How to make a copy of it? Need a clone function: – B *copy = bp->clone();

226 What if you want to have a base class function access derived class information, kind of like this? – class Base { public: void func() { printf(“%d\n”, m_color); } }; class D1 : public Base { public: const int m_color; }; class D2 : public Base { public: const int m_color; }; – Obviously no way to access a derived class data member. What we really want to access is information, though. Accessing Derived From Base

227 Need to pass to base class ctor, or use a virtual function. – class Base { public: Base(int color) : m_color(color) {} void func1() { printf(“%d\n”, m_color); } void func2() { printf(“%d\n”, color()); } virtual int color() const = 0; private: const int m_color; }; class D1 : public Base { public: D1() : Base(1) {} virtual int color() const { return 1; } }; class D2 : public Base { public: D2() : Base(2) {} virtual int color() const { return 2; } }; Which one is more efficient? Which one is less error-prone?

228 Can get efficiency and robustness this way: – class Base { public: Base() : m_color(color()) {} virtual int color() const = 0; private: const int m_color; }; class D1 : public Base { public: D1() = default; virtual int color() const { return 1; } }; class D2 : public Base { public: D2() = default; virtual int color() const { return 2; } }; – Well, not really. The derived type has not been constructed yet, so this is undefined behavior.

229 Could also be a reference: – struct E { virtual ~E() = default;... }; struct E1 : public E {... }; struct E2 : public E {... } struct Base { Base(E &e) : m_e(e) { m_e.some_method(); } // Okay? void func() { m_e.some_method(); } // Okay? E &m_e; }; struct D1 : public Base { D1() : Base(m_e1) {} E1 m_e1; }; struct D2 : public Base { D2() : Base(m_e2) {} E2 m_e2; };

230 (Co|Contra|In)variance Let’s say that we have class Animal and a class Dog. Dog derives from Animal. Is the Dog class a subtype of the Animal class? Does this code compile? – Dog d[10]; void foo(Animal *);... foo(d); Should it?

231 Problem? – Dog d[10]; void foo(Animal *ap) { ap[2].some_method();... } foo(d); Should an array of Dog objects be a subtype of an array of Animal objects?

232 Covariance: – If B is a subtype of A, then a type composed from B is a subtype of the same composition based on A. Contravariance: – If B is a subtype of A, then a type composed from B is a supertype of the same composition based on A. Invariance: – If B is a subtype of A, then a type composed composed from B is completely unrelated to the type of the same composition based on A.

233 How about this? – Dog *d[10]; void foo(Animal **ap) { ap[2]->some_method();... } foo(d); Should an array of Dog * be a subtype of an array of Animal * ?

234 How about this? – void foo(vector &); vector d;... // Populate d. foo(d); So here’s the implementation of foo(). – void foo(vector &v) { v.push_back(new Cat;); } How about this? – void foo2(const vector &); vector d;... // Populate d. foo2(d);

235 How about this? – Animal *get_animal(); void foo2(Dog *(*func)());... foo2(&get_animal); How about this? – Dog *get_dog(); void foo(Animal *(*func)());... foo(&get_dog);

236 How about this? – void addAnimal(Animal *); void foo2(void (*func)(Cat *)); … foo2(&addAnimal); How about this? – void addCat(Cat *); void foo(void (*func)(Animal *)); … foo(&addCat);

237 Is this okay? – struct A { void foo1(); }; struct B : public A { void foo2(); };... void (B::*ptm)() = &A::foo1; // Okay? void (A::*ptm)() = &B::foo2; // Okay?

238 Can be combined: – struct A {... }; struct B : public A {... }; struct X { A *foo1(); B *foo3(); }; struct Y : public X { B *foo2(); };... A *(Y::*ptm)() = &X::foo1; // Okay? B *(Y::*ptm)() = &X::foo1; // Okay? A *(Y::*ptm)() = &X::foo3; // Okay?

239 Is this okay? – class Base { public: virtual double func();... }; class Derived : public Base { public: virtual int func(); };

240 Suppose you have a class hierarchy. What should the return type of clone() be? – struct B { virtual ??? *clone() const; }; struct D : public B { virtual ??? *clone() const; } – struct Animal { virtual Group *getGroup() const; }; struct Bird : public Animal { virtual Flock *getGroup() const; }; struct Flock : public Group {... };

241 What about parameters? – struct X { … }; struct Y : public X { … }; struct Z : public X { … }; struct A { virtual void foo1(X *); virtual void foo2(Y *); }; struct B : public A { virtual void foo1(Y *); // Safe? Virtual void foo2(X *); // Safe? }; … X x; Y y; Z z; B b; A &ar(b); ar.foo1(&x); // ? ar.foo1(&y); // ? ar.foo1(&z); // ? ar.foo2(&x); // ? ar.foo2(&y); // ? ar.foo2(&z); // ?

242 C++ does not support contravariance of parameter types in overridden virtual functions.

243 Mutable Arrays/Vectors Immutable Arrays/Vectors Pointers-to- Members Return Types Parameters Type-safetyInvariantCovariantContravariantCovariantContravariant C++ supportPartialNoYesPartialNo

244 Plain Old Data (POD) C compatibility Nothing except data members.

245 Missing vtable/typeinfo Errors Caused by missing definitions of virtual functions. – $ cat foo.cpp class A { public: virtual void foo() const {} }; class B : public A { public: virtual void foo() const; }; int main() { B b; } $ g++ foo.cpp /tmp/ccg3JJkc.o: In function `B::B()': foo.cpp:(.text._ZN1BC1Ev[B::B()]+0x1c): undefined reference to `vtable for B‘ collect2: ld returned 1 exit status

246 Efficiency Are virtual functions slow? If you don’t use a virtual function, you almost always need an if-statement anyway. – // Do some prior computation to set-up // the if-test. if (…) { foo->do_version_A(); } else { foo->do_version_B(); } – Versus: foo->do_it();

247 [Show cost_of_virt.] Virtual call: – for (int i = 0; i foo(); }

248 Non-virtual (regular) call: – for (int i = 0; i type); case Base_nv::D1: static_cast (a[i])->foo(); break; case Base_nv::D2: static_cast (a[i])->foo(); break; } } Inlined: – for (int i = 0; i type); case Base_nv::D1: static_cast (a[i])->inline_foo(); break; case Base_nv::D2: static_cast (a[i])->inline_foo(); break; } }

249 Derivation for Implementation Suppose a car has an engine. You need an engine in your car. – Also, engines need a start() method, but also you want a start() method on your car. So you could do this, and automatically get your start method. – class Engine { public: void start(); … }; class Car : public Engine { public: // Get the start() method for free. … }; Does this obey the LSP? – Probably not. But you can fix by using private inheritance. – Or, just don’t do it. Use composition/aggregation. class Car { private: Engine engine; };

250 Private and Protected Inheritance To derive for implementation, use private or protected inheritance: – // All in B are private now. class A : private B { … }; – // All in B is protected now. class A : protected B { … }; Can also selectively make more or less restrictive. – class B { void priv_func(); public: void foo(); }; class A : public B { private: using B::foo; // Make B::foo private. }; class A2 : private B { public: using B::foo; // Make B::foo public. };

251 Also, something that is not publically inherited will not be automatically converted to base class pointer or reference: – class Base {... }; class Derived_priv : private Base {... }; class Derived_pub: public Base {... }; void foo(Base &); Derived_priv dpriv; Derived_pub dpub; foo(dpriv); // Syntax error. foo(dpub); // Okay.

252 Interfaces vs. Classes What is the difference between an interface and a class? In common OOP usage: – Interface: What the methods are named, the parameters they take, return types, and the semantics. – Class: The implementation of the interface, the actual data members, method implementation code, etc.

253 Does Java support polymorphism/virtual-functions? 1.A Java interface cannot be instantiated, any C++ class with a non- overridden pure virtual function cannot be instantiated. 2.All Java methods are polymorphic. In C++, only virtual functions are polymorphic. 3.In C++, individual functions can be specified as part of the interface, by making them pure virtual. In Java, it is all (interface), or none (class). Does Java have interfaces? Does C++ have interfaces? In C++, there is greater ability to mix and match the features of interfaces and classes, so interface is somewhat implicit. – Virtual functions and abstract base classes can be used to make them more explicit. – A class with just pure virtual functions and no data members is essentially an interface. Note that Java abstract base class has some relationship.

254 Example: 1.You properly separate interface from class. 2.You create an interface. –Java: Use interface keyword. –C++: Make all functions pure virtual and make the class have no data members. 3.Create 4 classes that implement the interface. 4.You notice that all 4 classes have the same implementation of a particular function. 5.What do you do? –Java: Create a new base class that implements the interface. –C++: Move the function into the interface class as non-pure virtual function. –In C++, the decision as to whether or not a particular function is part of the interface or implementation (class) is made on a function-by-function basis.

255 Java: – interface I { // Everything in here is part of interface. … }; – class A implements I { // Everything here is part of the implementation. … }; C++ – class Base { public: virtual f1() = 0; // Part of interface. virtual f2() = 0; // Part of interface. void common_func(); // Part of interface AND // implementation. All // classes share the same // implementation, so make it // non-virtual. … };

256 What is the interface of this class? – struct A { void f(int); };

257 Do these two classes have the same interface? – struct D1 { void f(int); }; struct D2 { void f(int); }; Do E1 and E2 have the same interface? – struct Interface { virtual void f(int) = 0; ; struct E1 : public Interface { virtual void f(int) { … } }; struct E2 : public Interface { virtual void f(int) { … } };

258 When we use the word ‘interface’, we usually mean to include semantics. But the programming language only enforces syntactic. Program to the interface, not to the implementation.

259 Fragile Base Class Often, seemingly safe changes to a base class cause things to break in the derived classes. Example:

260 Someone in your company, but in a different division, writes a string class. – class String { public: virtual void append(char); void length() const { return strlen(buf); } protected: char *buf; }; Your boss says that your app runs too slow. You look into, and discover that the length() function is taking 90% of the time. – You don’t control the String class. The author, Joe, is unresponsive because the app for his division runs fine. – What do you do? Steal Joe’s office chair and hold it hostage till he fixes String. Tell your boss that you need to buy faster computers. Tell your boss that you need to create your own standalone String class. Derive an optimized version from String.

261 You make it more efficient for length: – class String2 : public String { public: virtual void append(char) { m_length++; this->String::append(c); } void length() const { return m_length; } private: int m_length; }; Good? Obeys LSP? – void foo(String *s); String2 s; foo(&s); // Okay? s.length();

262 Joe decides to add a convenience function to allow the user to append a complete string at once. – class String { public: virtual void append(char); void append(const char *str) { for (int i = 0; i append(str[i]); } } void length() const { return strlen(buf); } private: char *buf; }; Okay? – Cannot call append(const char *) on String2 object (without a using declaration in String2), but that won’t break your existing code.

263 Joe decides that it is much faster to append the complete string at once. – class String { public: virtual void append(char); void append(const char *str) { strcat(buf, str); } void length() const { return strlen(buf); } protected: char *buf; }; Does this still obey LSP?

264 Dynamic Type vs Static Type Static type: What something is declared as, statically. Dynamic type: What something actually is (i.e., the most derived type). – class A { … }; class B1 : public A { … }; class B2 : public A { … }; A *ap = …; // Static type of *ap is A, but the // dynamic type is not known at // compile time. (*ap).foo();

265 In general, C++ is a statically-typed language. Dynamic typing is enabled by polymorphism. – struct A { virtual void foo(); }; struct B : public A { virtual void foo(); }; B b; A *ap = &b; (*ap).foo();

266 Run-Time Type Identification (RTTI) Sometimes you need to know the actual type of an object, when you have just a pointer to the base class. How do you do inheritance in C?

267 Inheritance in C: – struct A { int a_member; }; struct B1 { struct A A_sub; int b1_member; }; struct B2 { struct A A_sub; int b2_member; }; Upcasting and downcasting: – struct B1 b1; B1_ctor(&b1); A *ap = (A *) &b1; // Upcast B1 *b1p = (B1 *) ap; // Downcast A *ap = …; // Pointer to A obtained somehow. B2 *b2p = (B2 *) ap; // Safe?

268 Inheritance in C: – struct A { int a_member; }; struct B1 { struct A A_sub; int b1_member; }; struct B2 { struct A A_sub; int b2_member; }; How do we be safe? Try to make sure of type. – A *ap = …; // Pointer to A obtained somehow. if (/* ap is really a B1 */) { B1 *b1 = (B1 *) ap; // Do something with b1 that is B1 specific. } else if (/* ap is really a B2 */) { B2 *b2 = (B2 *) ap; // Do something with b2 that is B2 specific. }

269 Use type ID of some kind. – struct A { enum { T_B1, T_B2 } id; int a_member; }; struct B1 { struct A A_sub; int b1_member; }; struct B2 { struct A A_sub; int b2_member; }; Check ID before downcast. – A *a = …; // Pointer to A obtained somehow. if (a->id == T_B1) { B1 *b1 = (B1 *) a; // Do something with b1 that is B1 specific. } else if (a->id == T_B2) { B2 *b2 = (B2 *) a; // Do something with b2 that is B2 specific. }

270 Error prone: where is the ID set? – struct A { enum { B1_T, B2_T } id; … }; struct B1 { struct A A_sub; }; struct B2 { struct A A_sub; }; B1 b1; // No constructor b1.A_sub.id = B1_T;

271 If using C++, can do it in the constructor. – struct A { const enum { B1_T, B2_T } id; A(enum Id i) : id(i) {} … }; struct B1 { B1() : A_sub(B1_T) {} struct A A_sub; }; struct B2 { B2() : A_sub(B2_T) {} struct A A_sub; }; B1 b1;

272 What are more idiomatic C++ solutions? What does this do? – struct A { virtual ~A() {} }; struct B1 : public A { … }; struct B2 : public A { … }; B1 b; A *a = &b; B2 *bp = dynamic_cast (a); bp == ??; // What is the value of bp? Can use dynamic casting. – dynamic_cast downcast only works on polymorphic types.

273 Can also use RTTI: – #include struct A { virtual ~A() {} }; struct B1 : public A { … }; struct B2 : public A { … }; B1 b; A *a = &b; if (typeid(*a) == typeid(B1)) { … } else if (typeid(*a) == typeid(B2)) { … } else if (typeid(*a) == typeid(B3)) { … } The typeid operator returns a reference to an object of class type_info.

274 The type_info object has a string name that can sometimes be helpful for debugging. – struct A { virtual ~A() {} }; struct B1 : public A { … }; struct B2 : public A { … }; B1 b; A *a = &b; cout << typeid(*a).name() << endl;

275 There is no standard meaning for the string, but usually it’s meaningful and usually it can be decoded. In g++, you can demangle by doing: – #include #include #include class A { public: virtual ~A () {} }; class B : public A { }; int main() { B b; A *ap = &b; int ec; const char *demangled_name = abi::__cxa_demangle(typeid(*ap).name(), 0, 0, &ec); printf("%s\n", demangled_name); free((void *) demangled_name); }

276 Is this efficient? – A *a = …; // Obtained somehow. if (typeid(*a) == typeid(B1)) { … } else if (typeid(*a) == typeid(B2)) { … } else if (typeid(*a) == typeid(B3)) { … } … { } else if (typeid(*a) == typeid(B100)) { … } Solution?

277 You could push the code into the object: – // Original version. if (typeid(*a) == typeid(B1)) { // Some code to do XYZ. } else if (typeid(*a) == typeid(B2)) { // Some code to do ABC. } – // Code moved into a virtual function in the // object. virtual void B1::doit() { // Code to do XYZ. } virtual void B2::doit() { // Code to do ABC. } … a->doit(); // Outside of the object. Disadvantage? – Intrusive, however.

278 The problem is to efficiently map from the type to the code that should be executed for that type. – struct Code { virtual ~Code() = default; }; struct Code_A { virtual void operator()(A *) const = 0; }; struct Code_A_code1 : public Code_A { virtual void operator()(A *) const { // Do something specific. } }; map type_map; Code &code = *type_map.lookup(&typeid(*a)); dynamic_cast (code)(a); – Okay? In order to efficiently store type_info in a map, what operation do we need? – The type_info object has before() method.

279 Use the before() method to create a comparator object. – struct Cmp { bool operator()(const type_info *ti1, const type_info *ti2) { return ti1->before(*ti2); }; map type_map; Code &code = *type_map.lookup(&typeid(*a)); code(a); type_info objects do not have a copy constructor nor an assignment operator. This will fail: – map table;

280 In C++11, can use type_index, which is a convenience wrapper. – #include #include #include #include #include using namespace std; int main() { map table; table.insert(make_pair(type_index(typeid(int)), "It's an int.")); table.insert(make_pair(type_index(typeid(double)), "It's a double.")); table.insert(make_pair(type_index(typeid(char)), "It's an char.")); cout second second second << endl; }

281 Can also use the hash code, for hash tables (C++11): – size_t type_info::hash_code();

282 Object Slicing The derived part of objects is sliced off when used non-polymorphically. May not be avoidable, be aware! – struct Base { ~Base(); virtual void method(); }; struct Derived : public Base { ~Derived(); virtual void method(); }; Derived *dp = new Derived; Base *bp = dp; delete bp; // Calls?

283 What about this? – struct Base { virtual void method(); }; struct Derived : public Base { virtual void method(); }; Derived d; void foo(Base b) { b.method(); } foo(d); // Calls which method()?

284 What happens here? – struct Base { // … int base_var; }; struct Derived : public Base { // … int derived_var; }; int main() { Derived d1(…), d2(…); Base &b1_ref(d1), &b2_ref(d2); b1_ref = b2_ref; } Solution?

285 No great solution. RTTI seems to be the best choice. – struct Base { Base(int b) : base_var(b) {} virtual Base &operator=(const Base &) = 0; int base_var; }; struct Derived : public Base { Derived(int b, int d) : Base(b), derived_var(d) {} virtual Derived &operator=(const Base &); Derived &operator=(const Derived &); int derived_var; }; Derived &Derived::operator=(const Base &o) { return this->operator=(dynamic_cast (o)); } int main() { Derived d1(1, 2), d2(3, 4); Base &b1_ref(d1), &b2_ref(d2); b1_ref = b2_ref; }

286 Forward and Backwards Compatibility What do they mean? Suppose we are writing a web browser. Should it be able to read in old versions of HTML? – How to ensure? Suppose you are writing a web browser. Should the browser be able to handle future versions of HTML? – How do we ensure this? Forward compatibility: The ability of an application to accept future versions of input. Backward compatibility: The ability of an application to accept previous versions of input. Which is harder?

287 ABI (Application Binary Interface) vs. API Consider a module within an application. – You design the module interfaces carefully. – Version 2, implementation changes, but not the interfaces. Does the rest of the application need to be modified? Does it need to be recompiled? – Why does this matter?

288 Original: – class A { public: void foo(); private: int i; }; Modified: – class A { public: void foo(); private: int i, j; }; Client code: – A a; Recompile?

289 Original: – class A { public: void foo(); private: int i; }; Modified: – class A { public: void foo(); void foo2(); private: int i; }; Client code: – A a; a.foo(); Recompile?

290 Original: – class A { public: virtual void foo(); private: int i; }; Modified: – class A { public: virtual void foo(); virtual void foo2(); private: int i; }; Client code: – A a; a.foo(); Recompile?

291 Original: – void A::foo() { printf(“%d\n”, 1234); } Modified: – void A::foo() { printf(“%d\n”, 5678); } Client code: – A a; a.foo(); Recompile?

292 In general: – Header file change  recompile – Implementation file change  recompile – Basically, this is what the standard states. However...more specifically: – Existing machine code breaks  recompile. – Existing machine code doesn’t break  recompile. – Platform dependent, NO GUARANTEES. × ×

293 Is Node v2 backwards binary compatible with v1? – struct Node { char version; double x; int i; int p1, p2, p3; // Padding for extensibility. }; struct Node { // v2 char version; double x; int i; double y; }; [See /usr/include/gtk-2.0/gtk/gtkwindow.h ]

294 Can also be achieved with wrappers (PImpl idiom). – // A.hpp class Aimpl; class A { public: void method1(); private: Aimpl *impl; }; – // A.cpp void A::method1() { impl->method1(); } – // Aimpl.hpp class Aimpl { … }; – What does a client need to include? #include “A.hpp” #include “Aimpl.hpp” // Needed? – Modify A.cpp: Recompile rest of program? – Modify Aimpl.hpp: Recompile A.cpp? Recompile rest of the program?

295 Binary compatibility is important in these situations: – Large application with plug-ins/modules/extensions: Want to ship bug fixes/new versions to customers. With no binary compatibility, what happens? With binary compatibility? – Designing an OS: When you upgrade the OS, what happens to apps? – Libs and dlls: What happens if there is a bug in the C library on Windows or Linux? Binary compatibility is guaranteed by adhering to an ABI (Application Binary Interface).

296 check makeup time

297 What about linking? – Not an issue as long as run-time linking is used.

298 TYPES

299 Declarations Declarations associate a name with a type. A declaration does not actually allocate storage, while a definition does. For any given variable or function, there must be only a single definition, but there may be multiple declarations. (One Definition Rule)

300 Names Maximum length is implementation-defined. Do not use leading underscores or double underscores. – Do not use _DEBUG. Why not? Rule of Thumb: Short names in short scopes. Long names in long scopes.

301 Booleans bool Two values: true or false – What is relation of truthiness to numerical and pointer values? // What values do they get? int i = true, j = false; if (10) {... } else {... } if (-10) {... } else {... } if (0) {... } else {... } if (0.0) {... } else {... } int *a =...; if (a) {... } else {... } if ("") {... } else {... } true has the value 1, false value 0. Non-zero is true, 0 is false. Floating point 0.0 is also false. Non-null pointer is true, otherwise false. The type of the string literal (“”) is an array, but it decays to a pointer to the beginning of the literal. Since it is non-null, it is true.

302 Character Types char holds a character of the implementation’s character set. sizeof(char) is defined to be 1. – What if a character takes 12 bits? Does sizeof a char return 1.5? May be signed or unsigned, depending on implementation. – char c = 0; c = c – 1; // Output below depends on signedness of char. printf("%d\n", int(c)); If you need something specific, can specify it. – signed char c = 0; c = c – 1; printf(“%d\n”, (int) c); // Always -1. – unsigned char c = 0; c = c – 1; cout << int(c) << endl; // Always 255. 'a' is a character literal. 'abcd' is a multicharacter literal.

303 Integer Types Integer types: – int, short, long, long long (usually 64-bit) – signed, unsigned Literals: – 0xff, 123, 073, 123U, 1234L, 1234LL – Note that there is no way to specify a literal short, but you can cast: short(1). What does this print? – #include int main() { int i = 1000000; printf("%d\n", (4000*i)/4000); } – Prints -73741. – [Show overflow/] Technically, overflow of signed integers is undefined. Commonly assumed to be benign, however. If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined, unless such an expression is a constant expression (5.19), in which case the program is ill formed. [Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. ]

304 Floating-Point Types Floating point types: – float, double (usually 8 bytes), long double (usually more than 8 bytes) 3.14 (defaults to double), 1.23f, 3.4L float pi_f = 3.14f; double pi_d = 3.14; long double pi_l = 3.14L; printf(“%f, %f\n”, pi_f, pi_d); printf("%lf\n", pi_f); printf("%lf\n", pi_l); // Okay? printf("%Lf\n", pi_l); // Okay? Alignment is to 8, usually, for doubles. How are floating point numbers actually represented, in terms of actual bits?

305 Type Aliases typedef : – typedef char *foo; – typedef long long int64; – Syntax rule to remember is that the name of the type goes where the name of the variable would normally go. Alias declaration (additional functionality with templates) (C++11): – using foo = char *; – using int64 = long long;

306 Can be used to define types for arrays: – typedef int array_t[5]; using array2_t = int [5]; – The length is part of the type. Can also be used define function types and function pointer types. – typedef int f(double); using fp = int (*)(double); int func(double); f foo; // What does this do? foo = func; // Okay? fp foo2; // What does this do? foo2 = func; // Okay?

307 Literal Constants If you write: – printf(“%d\n”, 15); Where are such constants stored in the executable? – Some constants are immediate operands (stored in the instruction). – Some are stored in data segment.

308 Structures Structure defined with: – struct foo { int i; double x; }; Fields are accessed with: – struct foo f, *fp = &f; fp->x and f.x; Initialized like this (same as arrays): – struct foo f = {1, 3.14}; Can be returned, assigned, etc. – struct foo g; g = f; – struct foo f() { struct foo f;...; return f; } struct foo obj; obj = f(); // Dangerous? – Okay, since it is returned by value.

309 Structures can have padding between fields, so the size of a structure is typically more than the sum of the size of each field. – Purpose of the padding is to maintain alignment. – Typically, a variable must start at an address that is a multiple of the size. There is also padding at the end of a struct. – For arrays, discussed later. Type equivalence: – Does this compile? – struct T1 { int i; }; struct T2 {int i;}; T1 *p1 =...; T2 *p2 = p1; – Does not compile, since they are different types even with same members. Let’s suppose you want to put an array in a struct, but the size might be different. What do you do? – Flexible array member. – struct foo { int i; double a[]; }; struct foo *fp = malloc(sizeof(struct foo) + n*sizeof(double)); fp->a[n – 1] = 3.14;

310 Can you make this compile? – struct A { int i; B b_field; }; struct B { double x; A a_field; }; Similar case: – struct A { int i; struct A a; // Need the struct? }; – Can get same effect: struct A { int i; A *inner; }; Structures can refer to each other recursively using pointers, but not contain each other recursively. One link of the recursion must be by pointer.

311 Enumerations Holds a set of values specified by the user. – enum state { LETTER = 1, SPACE }; Why might you want to begin with 1? – The values can be used as constants: foo = SPACE; int a[SPACE]; // Array of length 2. – Can reset. enum Color { RED = 1, BLUE, GREEN = 1 };

312 The scope of an unscoped enumerator is the same as enumeration itself, and also in the “enum” scope. – enum PotionType { HEALING, SPEED, POISON }; enum StatType { DEXTERITY, HEALTH }; int HEALTH = 10; // Error. StatType st = HEALTH; StatType st = StatType::DEXTERITY st2 = DEXTERITY; enum WandType { SPEED, FIREBALL }; // Error. C++11 adds scoped enumerations (enum classes): – enum class PotionType { HEALTH, SPEED, POISON }; enum struct StatType { DEXTERITY, HEALTH }; int HEALTH = 10; StatType st = StatType::HEALTH; PotionType pt = PotionType::HEALTH;

313 Enumerations can be used in overloading: – enum Color { R, G, B }; void foo(Color); void foo(int); Color c; foo(c); foo(1); Unscoped enums will implicitly convert to an integral type, but not scoped. – void goo(int); goo(c); // Okay, implicit conversion. enum struct Vehicle { CAR, TRUCK } v(CAR); goo(v); // Error.

314 C++11 allows you to specify the size of an enum: – enum Color : char { R, G, B }; – enum Part : char { Widget = 10000 }; // ? If you don’t specify it: – For unscoped enums, the type is unknown. – For scoped enums, it is int. You can also forward declare enums in C++11, but you must specify the size: – enum Color; // Error. enum Color : char; // Okay. // Okay, defaults to int. enum class AccountType;

315 Lvalues and Rvalues Some values: – 1 89 a b + c sin(3.1) Do all values have equal status? – Can a appear anywhere that 89 can appear? Assume a has been defined as an int.

316 Some values have storage associated with them. You can assign to them. – a = 2; Others are just values. – 2 = a;

317 References A reference is an alternate name, or alias. Arguably syntactic sugar. Implemented with pointers: At the implementation level, a pointer that doesn’t look like one. Defines another name for a variable. – int i, &alias = i, &alias2(i); i = 2; alias = 3; // Accessing the same variable. const int &i = 1; // Okay? int &j = 1; // Okay? – Initializer of non-constant reference must be lvalue. – Initializer of constant reference may be expression. Functions that return references can be used on the left-hand side of an assignment. – double &at(int i) { static double a[10]; return a[i]; } at(1) = 3.14159;

318 Cannot be re-bound, unlike a pointer. – int &i = j; i = &k; // Error. &i = k; // Error.

319 Pointers Exampless: – int *i_ptr, **i_pptr, ****i_pppptr; A *a_ptr; char *buf; Is a pointer just an address? – A type that points to an lvalue of another type. Essentially a typed address. Address-of operator ( & ): What can you take the address of? – Smart-alecky answer: Anything that has an address (i.e., any lvalue, more or less). – int var; &var, &(*ptr), &(ptr + 2), &(*(ptr + 2)), &(*(int *) 0xfff01234) – Address of reference: int var, &ref(var), &ref2 = var; &var is the same as &ref. – int i; int **ip = &(&i); int i, *ip = &i, **ipp = &ip; – int *ip = &(1 + 2); Dereference operator ( * ): What can you dereference? – Anything that is of pointer type.

320 Example of using pointers to pointers: – Suppose you have a singly linked list [interactive]: struct Node { int value; Node *next; }; Node *head = 0; – One way to append to it: Node *end = 0; void append(Node *n) { n->next = 0; if (end == 0) { head = end = n; } else { end->next = n; end = n; } } – Another way: Node **end = &head; void append(Node *n) { n->next = 0; *end = n; end = &n->next; }

321 Function Pointers Suppose you have a sort function, kind of like: – void sort(int *array) { … } Can you write code that you can use for both ints, doubles, or your own struct type? – [Editor] – // Sort in ascending order. void sort(void *array, int n, int sz, bool (*less)(void *, void*)) {... // Compare i-th and j-th element. char *a = (char *) array; if ((*less)(a + i*sz, a + j*sz)) {... } – bool Person_less(void *a, void *b) { Person *p1 = (Person *) a; Person *p2 = (Person *) b; return strcmp(p1->name, p2->name) < 0; }... Person *table = malloc(n_people*sizeof(Person));... sort(table, n_people, sizeof(Person), Person_less);

322 Suppose you now want to be able to sort in increasing order or decreasing order. What do you do? – Change the comparison function. – // Sort in ascending order. void sort(void *array, int sz, bool (*less)(void *, void*)) {... // Compare i-th and j-th element. char *a = (char *) array; if ((*less)(a + i*sz, a + j*sz)) {... } – bool Person_greater(void *a, void *b) { Person *p1 = (Person *) a; Person *p2 = (Person *) b; return strcmp(p1->name, p2->name) > 0; }... Person *table = malloc(n_people*sizeof(Person));... // Sort in descending order. sort(table, sizeof(Person), Person_greater);... // Sort in ascending order. sort(table, sizeof(Person), Person_less);

323 Can be reassigned, of course: – int foo1(double x) {... } int foo2(double x) {... } void foo3(double x) {... } int (*fp)(double); fp = &foo1; (*fp)(3.14); // Calls foo1(). fp = &foo2; (*fp)(3.14); // Calls foo2(). Types must match: – fp = &foo3; // Syntax error.

324 Null Pointers What is the value of i ? – char *p = 0; int i = int(p); What is the value of a null pointer? – It's actually unspecified. But wait, is it not 0? – Not really. 0 is a special code to the compiler. When it is used in a pointer context, the compiler automatically converts it to whatever the null pointer value is. Consider: – char *p = 0; int i = int(p); // Is i 0? – int zero = 0; char *p = (char *) zero; // Is p null? – char *p = 0; int *i = 0; (unsigned long long) p ?= (unsigned long long) i In C++11, a new keyword was introduced, nullptr. It’s best to use this.

325 What about NULL ? – It’s a macro. – Let’s assume it is defined as (void *) 0. Does this work? char *p = NULL; – Let’s assume it is defined as 0. Does this work? char *p = NULL; – On Linux, it is defined as follows: #ifndef _LINUX_STDDEF_H #define _LINUX_STDDEF_H #undef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #endif

326 Consider the execlp() system call: – int execl(const char *, const char *arg0,...); execl(“./a.out”, “a.out”, “arg1”, “arg2”, 0); Is this correct usage? – Not correct usage because the compiler has no way of knowing that the last argument is actually a null pointer. So need to cast. – execl(“./a.out”, “a.out”, “arg1”, “arg2”, (const char *) 0);

327 Arrays Must be contiguous in memory. Define one like this: – int a[4] = { 1, 2, 3, 4 }; int a[10]; // Initialized? int a[] = {1, 2}; int a[2] = {1, 2, 3}; // Error int a[2] = {1}; // Remainder are 0 initialized. // Technically an error, but a common extension. int a[0]; Can take the sizeof. What does this print? – int a[4]; printf(“%d\n”, sizeof a); printf(“%d\n”, sizeof(int [2000*1000*1000])); – Prints: 16 -589934592 – // Should be: printf(“%zu\n”, sizeof(int [2000*1000*1000]));

328 Are arrays passed in and returned by copy or reference? – void foo(int a[10]) { a[9] = 0; } a[9] = 1; foo(a); // What is a[9] now? – // What does the return type of foo2() need to // be?... foo2() { static int a[10]; return a; } – You can’t pass arrays, actually what you is a pointer to the first element. So passing arrays is essentially pass-by-reference. Which lines compile? – void foo(int a1[10]) { int a2[10]; a2 = 0; // ??? a1 = 0; // ??? } How do you pass in and return arrays by copy then? – Wrap in a struct: struct Array { int a[10]; }; Array foo(Array a) {...; return some_array; }

329 Type of an Array What is the type of an array? – int a[2]; – Trick question: The type of an array is a just “an array of the contained type”. It is NOT a pointer. However, it very easily “decays” into a pointer pointing to the first element. – int a[4], *ap = a; void foo(int *); foo(a); Note that the & of an array is not the same: – int *p = &a; // Syntax error. More examples: – typedef int array_t[4]; typedef int *ptr_t; array_t a; // Defines an array. ptr_t ip; // Defines a pointer to an int.

330 Arrays and Pointers Arrays and pointers are closely related. Pointer arithmetic is closely related to array indexing. – Assume that we have: int a[10]; int *ip = &a[0]; – Then a[2] is equivalent to *(ip + 2) which is equivalent to *(a + 2). Addition and subtraction: – int a[10], *ip = a; // What does ip point to? int *ip2 = ip + 3; // What does ip2 point to? int *ip3 = ip2 – 1; // ? int i1, i2; int n = &i1 - &i2; // Okay? int nn = &a[10] - &a[3]; // Okay? int n2 = &a[3] - &a[10]; // Okay? int n3 = &a[3] + &a[1]; // Okay? int a2[3]; int n4 = &a[3] - &a2[0]; // Okay?

331 Which ones are okay? – int *ip1 = …, *ip2 = …; ip1 + 2; ip1 + ip2; 2 + ip2; ip2 – 1; 2 – ip1; ip2 – ip1; Subtracting two pointers into an array is the same as subtracting the indices: – &a[i] - &a[j] == &(*(a + i)) – &(*(a + j)) == (a + i) – (a + j)) == (a – a) + (i – j) == i - j

332 Pointers and Memory Layout Consider a variable like this. How is it laid out in memory? – int i = 0x01020304, *i_ptr = &i; What is byte-ordering? What kinds can you have? – Which is big-endian and which is little-endian? How many different orderings are there? What is the value of i_ptr ? 3 4 1 2 PDP-11 1 2 3 4 100 101 102 103 Address 4 3 2 1 Memory of variable i One possible layout Another possible layout

333 What is printed out? – int i = 1; char *p = (char *) &i; printf(“%d\n”, (int) *p); 1 0 0 0 Increasing address One possible layout 0 0 0 1 Memory of variable i Another possible layout

334 How do you swap byte order? [Editor] – int i =...; i = ((i >> 24)&0x000000ff) | ((i >> 8)&0x0000ff00) | ((i << 8)&0x00ff0000) | ((i << 24)&0xff000000); – int i =..., j; char *p1 = (char *) &i, *p2 = (char *) &j; p2[0] = p1[3]; p2[1] = p1[2]; p2[2] = p1[1]; p2[3] = p1[0];

335 Complicated Definitions/Declarations Array of function pointers to functions that take one double parameter and return an int. – int (*a[10])(double); A function that take an int parameter and returns a function pointer to a function that takes a double and returns an int. – int (*f1(int i))(double){ … } A function that takes an int and returns a pointer to an array of 10 ints. – int (*func(int i))[10] {... } Array of 10 function pointers to functions that take an int parameter and returns a function pointer to a function that takes a double and returns an int. – int (*(*a[10])(int))(double);

336 When in doubt, use typedefs. – Array of function pointers to functions that take one double parameter and return an int. int (*a[10])(double); typedef int (*fp_t)(double); fp_t a[10]; – A function that take an int parameter and returns a function pointer to a function that takes a double and returns an int. int (*f1(int i))(double){ … } typedef int (*fp_t)(double); fp_t f1(int i) {... } – A function that takes an int parameter and returns a pointer to an array of 10 ints. int (*func(int i))[10] {... } typedef int (*array_ptr)[10]; array_ptr func(int i) {... } – Array of function pointers to functions that take an int parameter and returns a function pointer to a function that takes a double and returns an int. int (*(*a[10])(int))(double); typedef int (*fp_t)(double); typedef fp_t (*fp2_t)(int); fp2_t a[10];

337 Multidimensional Arrays Defining multidimensional arrays: – int a[2][3] = { 1, 2, 3, 4, 5, 6 }; – int a[10][20]; – They are really arrays of arrays. For example, int a[2][3] is really an array of size 2 of arrays of size 3. What is the type of the result of the index operation a[0][0] ? What is the type of the result of the index operation a[0] ? – This is two indexing operations. a[1][2]

338 Arrays have rows and columns. Memory, however, is linear. Thus, a 2-D array must be “linearized” to be stored in memory. There are theoretically many ways to do linearization, but only two are common. – Which one does C/C++ use? a 0,0 a 0,1 a 0,2 a 1,0 a 1,1 a 1,2 Array a[2][3] a 0,0 a 0,1 a 0,2 a 1,0 a 1,1 a 1,2 Row 0Row 1 a 0,0 a 1,0 a 0,1 a 1,1 a 0,2 a 1,2 Col 0Col 1Col 2 Col 0 Col 1 Col 2Col 0Col 1Col 2 Row 0Row 1 Row 0Row 1Row 0Row 1 Row major Column major Increasing address

339 Another way to look at it. a 0,0 int a[2][3]; a 0,1 a 0,2 a 1,0 a 1,1 a 1,2 Row 0Row 1 a 0,0 a 1,0 a 0,1 a 1,1 a 0,2 a 1,2 Col 0Col 1Col 2 Col 0 Col 1Col 2Col 0Col 1Col 2 Row 0Row 1 Row 0Row 1Row 0Row 1 Row majorColumn major a 0,0 a 0,1 a 0,2 a 1,0 a 1,1 a 1,2 a 0,0 a 0,1 a 0,2 a 1,0 a 1,1 a 1,2

340 Puzzle Question Array indexing is equivalent to pointer arithmetic at even a syntactic level, which leads to some strange things: – int a[10]; – a[2] equivalent to *(a + 2). a[2]  *(a + 2)  *(2 + a)  2[a]. – So, we should be able to write: 2[a] = 12345; // Right? Given an array int a[3][3], how many ways can you index the first element, using only the characters 0, [, ], and a? – a[0][0] – 0[a][0] – 0[a[0]] – 0[0[a]]

341 Pointers to Arrays Tricky concept, but especially useful as an educational exercise. – If you understand them, then you really understand pointers and arrays. ip is a pointer to what? ap is a pointer to what? Where does ip + 1 point? Where does ap + 1 point? ip ? bytes 11 ap int *ip =...; int (*ap)[3] =...; 1213 ? bytes 11 What is? sizeof ip == ?? sizeof ip[1] == ?? sizeof ap == ?? sizeof ap[1] == ?? sizeof ap[1][1] == ?? ap+1 212223 313233... ap+2... ip+1 21 31 ip+2

342 More examples: – int (*p1)[10]; int a1[10]; p1 = &a1; // Okay? p1[0] = 1; // Okay? (*p1)[0] = 1; // Okay? p1[0][0] = 1; // Okay? – int (*p2)[8]; p2 = &a1; // Okay? Can get some complex/weird looking definitions/declarations: – A function that returns a pointer to an array of 10 ints. int (*func())[10]; – An array of 10 pointers to functions that take an int and return a pointer to an array of doubles: double (*(*a1[10])(int))[20]; typedef double array_t[20]; typedef array_t *ptr_to_array_t; typedef ptr_to_array_t (*fp_t)(int); fp_t a2[10];

343 You can usually just use a pointer instead of a pointer to an array: – int a1[10], a2[10]; int *p; p = a1; p[1] = 1234; p = a2; p[1] = 1234; – int a1[10], a2[10]; int (*ap)[10]; ap = &a1; (*ap)[1] = 1234; ap = &a2; (*ap)[1] = 1234; However, in the case of multidimensional, dynamic arrays, pointers to arrays can do things that simple pointers cannot.

344 Can also have a reference to an array. – int a[10], (&alias)[10](a); – Mainly of use later on in templates.

345 Multidimensional Array Type Decay An array containing type T decays to a pointer to type T. – void f1(int *); int a[10]; f1(a); // Okay? – void f2(MyClass *); MyClass a[10]; f2(a); // Okay? – void f3(int **); int a[10][20]; f3(a); // Okay?

346 Derived *d[10]; Base **b = d; // Okay? Derived *d2[10][10]; Base ***b2 = d2; // Okay?

347 An array of ints decays to a pointer to an int. – int a[10]; // a decays to int *. void f1(int *); f1(a); // Works. An array of structs decays to a pointer to the struct. – MyClass a[10]; // a decays to MyClass *. void f2(MyClass *); f2(a); // Works. A multidimensional array is an array of arrays. So, a multidimensional array decays to a pointer to an array, not a pointer to a pointer. – int a[10][20]; // a decays to int (*)[20]. void f3(int (*ap)[20]); void f4(int **); f3(a); // Works. f4(a); // Syntax error.

348 Dynamic Arrays The “array of pointers” way. – Does each row need to have the same number of columns? 111112113... 121122123... 131132133... Number of columns Number of rows 2-D No.

349 ... Number of planes Number of rows 111112113... 121122123... 131132133... Number of columns 211212213... 221222223... 231232233... 311312313... 321322323... 331332333... 3-D Plane 0 Plane 2 Plane 1

350 The code for the “array of pointers” way. – void f_3ptr(int ***); int ***a = (int ***) malloc(np*sizeof(int **)); for (size_t i = 0; i < np; i++) { a[i] = (int **) malloc(nr*sizeof(int *)); for (size_t j = 0; j < nr; j++) { a[i][j] = (int *) malloc(nc*sizeof(int)); } } f_3ptr(a); for (size_t i = 0; i < np; i++) { for (size_t j = 0; j < nr; j++) { free(a[i][j]); } free(a[i]); } free(a);

351 If only one dimension needs to be dynamic, you can use a pointer to an array. – void f(int (*const a)[2][3]); int (*a)[2][3] = (int (*)[2][3]) malloc(np*sizeof(int [2][3])); f(a); free(a); 111112113 121122123 211212213 221222223 311312313 321322323... Plane 0 Plane 1 Plane 2 Row 0 Row 1 Row 0 Row 1 Row 0 Row 1 Col 0Col 1Col 2 a np planes Number of rows must be known at compile-time Number of columns must be known at compile-time

352 2D usage: A dynamically-determined number of rows, but a fixed number of columns. – // Pointer to an array of 10 columns. int (*a)[10]; // Use it as an array with n_rows and 10 columns. a = (int (*)[10]) malloc(sizeof(int [10])*n_rows); – a[0] refers to the first array of 10. a[1] refers to the second array of 10. a + 1 points to the second array of 10. a + 2 points to the third array of 10. a[0][2] refers to the third column in the first array. a[1][3] refers to the fourth column in the second array. (*(a + 2))[5] refers to the sixth column in the third array.

353 In C99, can use variable length arrays. The “array of pointers” way is slower, but more flexible.

354 C Strings A string in C is just an array of characters that is terminated by a 0 element. Note that you can have an array of characters that is not 0 terminated, and thus not really a string. What is the difference between? – char a1[] = “abcd”; const char *a2 = “abcd”; char a3[4] = {'a', 'b', 'c', 'd'}; sizeof a1 == ? sizeof a2 == ? sizeof a3 == ? a2[0] = 'z'; // Okay? a1 = "a"; // Okay? a2 = "b"; // Okay? a3 = "c"; // Okay? 5 Size of a pointer 4 No, can’t write to literal. Can’t assign to array. Yes. Can’t assign to array.

355 String Literals “hello“ // A string literal What is the type of “hello” ? – Type is “array of the appropriate number of const characters”: const char[6] – sizeof("hello") == 6 – What is the type in C? Is this okay code? – void error(char *s) { printf(“error: %s\n”, s); } … error(“Bad syntax”); – const char *foo() {return "hello";} Is this an error? – const char *str = "This is a long " "string.";

356 Void What is it used for? – Function returns. – Pointers to unknown types. Does this compile? – void *vp = …; char *cp = vp; What about arithmetic? – void *vp = …; void *vp2 = vp + 1; // Okay?

357 In C, does this compile? What about C++? – int f1() { return 1; } int main() { f1(1); } – int f2(); int main() { f2(1); } – int f3(void); int main() { f3(1); } In C, void in function definition is redundant, but not in a declaration. In C++, void in either a function definition or declaration is redundant. – int f4(void) { return 1; };

358 Constness const int foo = 30; int const foo = 30; // Same thing. – Cannot assign to foo. – foo = 10; // No. const int *foo; – Cannot assign to *foo, but can assign to foo itself. – *foo = 1; // No. foo = &some_int_var; // Okay. int *const foo = &some_int; – Cannot assign to foo (which is a pointer), but can assign to what is pointed to. – foo = &some_other_int_var; // No. *foo = 1234; // Okay. const int *const foo = &some_int; – Cannot assign to anything.

359 int ** const *** const * const *p; – p =...; // Okay? *p =...; // Okay? **p =...; // Okay? ***p =...; // Okay? ****p =...; // Okay? *****p =...; // Okay? ******p =...; // Okay? *******p =...; // Okay?

360 const Can only have const ref to temporary: – const int &i = 1; – const int &i = j*2; – double pi = 3.14; const int &i = pi;

361 constexpr In C++03, there is no way to cleanly say that something is a compile time constant. – const int i1 = 1; const int i2 = 3*4; const int i3 = MyClass ::RED; const int i4 = product_if_odd(3, 4, 5); Furthermore, you can never call a function to compute a compile time constant. C++11 has constexpr to fix this: – constexpr int i1 = 1; // Body must be just single return statement. constexpr int product_if_odd(int i, int j, int k) { return i%2 == 1 ? i*j*k : 0; } // Syntax error if foo() is not constexpr. constexpr int i2 = foo(3); constexpr int i3 = product_if_odd(3, 4, 5); // Okay.

362 C++14 greatly relaxes the restrictions on constexpr: – constexpr int count_a(const char *s) { int c = 0; for (; *s != '\0'; s++) { if (*s == 'a') { c++; } s++; } return c; }

363 Another C++14 example: – constexpr bool is_prime(int n) { for (auto i = 2; i*i <= n; i++) { if (n%i == 0) { return false; } } return true; }

364 Can also have constexpr arrays and objects, as long as the objects are of literal type. – struct A { int i, j; }; constexpr A foo() { return {1,2}; } constexpr A a(foo()); constexpr A aa[2] = { {1, 2}, {3, 4} };

365 Volatile [Show flag.] int *flags = some_special_hardware_address; while (true) { … if (*flags & 0x1) { … } … } Does above work? – Does *flags get reloaded every iteration? volatile int *flags = some_special_hardware_address; while (true) { … if (*flags & 0x1) { … } … }

366 restrict / __restrict__ [Show r_opt] Consider this function: – void f1(double *a, double *b, double *c) { *a = *a * *b + *c; *a = *a * *b + *c; } Does *b need to be reloaded from memory in the second statement?

367 decltype Sometimes you want to get the type of an object or expression, and use it in a declaration/definition. – int i; decltype(i) j; int *ip; decltype(ip) ip2; int &r = i; decltype(r) r2(j); // r2 is a reference. The decltype of an lvalue is a reference (except if it is just the variable). – int i1(11); decltype(i1) i2(22); // i2 is an int. decltype((i1)) r1(i2); // r1 is a ref. decltype(i1 + 1) i3(i2); // i3 is ?. decltype(*(&i1 + 1)) i4(i2); // i4 is ?. – const int c1(11); decltype(c1) c2(22); // c2 is a const int.

368 The decltype of a function is a function. Can use this to simplify function pointer definitions/declarations. – int f(double) { … } decltype(f) f2; // int f2(double); decltype(f) *f3(int) { … }

369 auto auto was originally just a storage class specifier indicating that storage should be non-persistent (stack): – void foo() { register int i1; extern int i2; static int i3; auto int i4a; int i4b; // Exactly the same. Since it was the default anyway, it was pretty useless.

370 It now has an additional new meaning, which is that the type of the variable being defined should be based on the type of the initializer. – auto i = 1; int &r(i); auto i2 = r; // ref or not? auto &i3 = r; auto *i4 = &r; auto i5 = &r; const int i6(1234); auto i7(i6); i7 = 567; // Okay or not? auto &i8(i6); i8 = 567; // Okay? – const int *const ip1(&i6); auto ip2(ip1); *ip2 = 567; // Okay? ip2 = &i; // Okay?

371 The deduced type must be consistent for every variable: – const int i(1234); auto i1(i), &i2(i); // Okay? Very handy for things like iterators: – for (map ::iterator it = map.begin(); …) { … } – for (auto it = map.begin(); …) { … } In C++14, can get the same rules for decltype as for auto : – decltype(auto)

372 Type Conversions Implicit conversions – They are “automatic”, in the sense that you don’t need to add anything to make them happen. – What are some? int to double Pointer to derived to pointer to base (upcast) Two situations where conversions come into play. 1.Converting to a given type, such as assignment or argument passing. 2.Two operands of an arithmetic operator. Arithmetic conversions: signed/unsigned combinations are tricky: – If both operands are same size, the signed is converted to the unsigned. – Otherwise, it’s more or less the smaller to the larger.

373 int vs. unsigned long – cout << -1 + 1UL << endl; cout << (-1 < 1UL) << endl; cout << -2 + 1UL << endl; cout << (-2 < 1UL) << endl; cout << -1 + 2UL << endl; cout << (-1 < 2UL) << endl; cout << -2 + 2UL << endl; cout << (-2 < 2UL) << endl; – On 32-bit Linux g++: -1 + 1UL == 0 -1 < 1UL == false -2 + 1UL == 4294967295 -2 < 1UL == false -1 + 2UL == 1 -1 < 2UL == false -2 + 2UL == 0 -2 < 2UL == false

374 int vs. unsigned long – cout << -1 + 1UL << endl; cout << (-1 < 1UL) << endl; cout << -2 + 1UL << endl; cout << (-2 < 1UL) << endl; cout << -1 + 2UL << endl; cout << (-1 < 2UL) << endl; cout << -2 + 2UL << endl; cout << (-2 < 2UL) << endl; – On 64-bit Linux g++: -1 + 1UL == 0 -1 < 1UL == false -2 + 1UL == 18446744073709551615 -2 < 1UL == false -1 + 2UL == 1 -1 < 2UL == false -2 + 2UL == 0 -2 < 2UL == false

375 long int vs. unsigned int – cout << -1L + 1U << endl; // L1 cout << -1L + 1U - 1 + 2LL << endl; // L2 cout << -1L + 1U + 2LL - 1 << endl; // L3 cout << -2L + 1U << endl; // L4 cout << (-1L < 1U) << endl; // L5 – On 64-bit: -1L + 1U == 0 -1L + 1U – 1 + 2LL == 1 -1L + 1U + 2LL – 1 == 1 -2L + 1U == -1 -1L < 1U == true – On 32-bit: -1L + 1U = 0 -1L + 1U – 1 + 2LL == 4294967297 -1L + 1U + 2LL – 1 == 1 -2L + 1U == 4294967295 -1L < 1U == false

376 int vs. unsigned int – cout << -1 + 1U << endl; // L1 cout << -2 + 1U << endl; // L2 cout << (-1 < 1U) << endl; // L3 – On 64-bit: -1 + 1U = 0 -2 + 1U = 4294967295 -1 < 1U = false

377 What does this print? – size_t s3 = 3, s5 = 5; size_t s10 = 10; long long ll10 = 10; s10 += s3 - s5; // L1 ll10 += s3 - s5; // L2 cout << s10 << “, “ << ll10 << endl; – size_t is 64-bit unsigned on 64-bit platforms, and 32-bit unsigned on 32-bit platforms. – long long is a 64-bit signed integer on both platforms. – On 64-bit: 8, 8 – On 32-bit: 8, 4294967304

378 What does this print? – cout << 2000000*2000*1L << endl; cout << 1L*2000000*2000 << endl; – Intel 32-bit with g++: -589934592 – Intel 64-bit with g++: -589934592 8000000000

379 bool conversions Does this print “Yes” or “No”? – int i = 10; if (i) { cout << “Yes” << endl; } else { cout << “No” << endl; } What about this? – int i = 10; if (i == true) { cout << “Yes” << endl; } else { cout << “No” << endl; }

380 Numerical Conversions 3.9.1/4 Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer. 4.5 Integral promotions [conv.prom] 1.An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; otherwise, the source rvalue can be converted to an rvalue of type unsigned int. 2.An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of its underlying type: int, unsigned int, long, or unsigned long. 3.An rvalue for an integral bitfield (9.6) can be converted to an rvalue of type int if int can represent all the values of the bitfield; otherwise, it can be converted to unsigned int if unsigned int can represent all the values of the bitfield. If the bitfield is larger yet, no integral promotion applies to it. If the bitfield has an enumerated type, it is treated as any other value of that type for promotion purposes. 4.An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true becoming one. 5.These conversions are called integral promotions. 4.6 Floating point promotion [conv.fpprom] 1.An rvalue of type float can be converted to an rvalue of type double. The value is unchanged. 2.This conversion is called floating point promotion. 4.7 Integral conversions [conv.integral] 1.An rvalue of an integer type can be converted to an rvalue of another integer type. An rvalue of an enumeration type can be converted to an rvalue of an integer type. 2.If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ] 3.If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bitfield width); otherwise, the value is implementation defined. 4.If the destination type is bool, see 4.12. If the source type is bool, the value false is converted to zero and the value true is converted to one. 5.The conversions allowed as integral promotions are excluded from the set of integral conversions. 4.8 Floating point conversions [conv.double] 1.An rvalue of floating point type can be converted to an rvalue of another floating point type. If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an implementation defined choice of either of those values. Otherwise, the behavior is undefined. 2.The conversions allowed as floating point promotions are excluded from the set of floating point conversions. 4.9 Floating-integral conversions [conv.fpint] 1.An rvrvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type. [Note: If the destination type is bool, see 4.12. ] 2.An rvalue of an integer type or of an enumeration type can be converted to an rvalue of a floating point type. The result is exact if possible. Otherwise, it is an implementation defined choice of either the next lower or higher representable value. [Note: loss of precision alue of a floating point type can be converted to an occurs if the integral value cannot be represented exactly as a value of the floating type. ] If the source type is bool, the value false is converted to zero and the value true is converted to one. 5/9 Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows: – If either operand is of type long double, the other shall be converted to long double. – Otherwise, if either operand is double, the other shall be converted to double. – Otherwise, if either operand is float, the other shall be converted to float. – Otherwise, the integral promotions (4.5) shall be performed on both operands. – Then, if either operand is unsigned long the other shall be converted to unsigned long. – Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; – otherwise both operands shall be converted to unsigned long int. – Otherwise, if either operand is long, the other shall be converted to long. – Otherwise, if either operand is unsigned, the other shall be converted to unsigned. – [Note: otherwise, the only remaining case is that both operands are int ]

381 Object Identity Let’s say that you have two references to two objects belonging to some struct (or class). How can you tell if they refer to the same object? – struct Foo { int i; double x; }; void some_func(const Foo &r1, const Foo &r2) { // Are r1 and r2 actually the same object? if (&r1 == &r2) {... } } Two objects are the same object if and only if they have the same address.

382 sizeof empty struct [empty_struct/] What does this print in C? – struct Empty {}; int main() { struct Empty a[10]; printf("distance: %d\n", (int) (&a[1] - &a[0])); } – This causes a numerical exception.

383 What is should sizeof return for this? – struct Empty {}; If it returned 0, then… – Empty a[10]; Empty *a1 = &a[1]; Empty *a2 = &a[2]; if (a1 == a2) { printf(“Same object!\n”); } &a[i] - &a[j] ?== (i – j)

384 OPERATORS AND EXPRESSIONS

385 Operators Arithmetic: + - / * % – -10/3 == ? -10%3 == ? – Must always be true: (a/b)*b + a%b == a. Relational: >= == != && || – Is this code safe? int *ip = …; if (ip != 0 && *ip == 1) { … } Negation: ! Increment and decrement: -- ++ Bitwise: & | ^ ~ > Assignment: = =+ =/ … – Value of an assignment operator is value of the result. – int a; printf(“%d\n”, a = 1); // Prints 1 printf(“%d\n”, 3*(a += 2)); // Prints 9. – Also an lvalue (but not in C): (a = 1) = 3;

386 Conditional expression: – i = a > b ? 1 : 2 Is this a syntax error? – i = f(1), g(2); sizeof, &var, * (dereference)

387 Any difference between these? – sizeof var; sizeof(var); sizeof(int *); sizeof int *;

388 Interlude Questions How do you align (round-up) a number to a multiple of another number? – 3 aligned to a multiple of 7? How do you swap the byte order of an integer?

389 Precedence and Associativity What is this code trying to do? Is it correct? – if (a << 1 + 1 == c & 0xf) { … } – Actual precedence: if (((a << (1 + 1)) == c) & 0xf) { … } Precedence is which operator gets applied first. – x*y + a – The * has higher precedence, so the y operand is bound to the *. Associativity is which operator gets executed first when the precedence is the same. – a + b + c (a + b) + c – a – b + c (a – b) + c – a + b – c (a + b) – c – a/b/c (a/b)/c – i = j = k = 1234; ((i = j) = k) = 1234; i = (j = (k = 1234)); // This is correct.

390 Tip: Look at the operand, not the operator. – A left associative operator means that an operand goes with the operator on the left. Suppose (hypothetically) that + was left associative and – was right associative. Then how would this be evaluated? – a – b + c a + b + c

391 Baking Recipe Prepare mixture A (takes 10 minutes). Let stand 50 minutes. Prepare mixture B (takes 20 minutes). Prepare mixture C (takes 30 minutes). Let stand 20 minutes. Whip B and C together producing D. Gently fold A into D. Expression: cake = make_A() FOLD make_B() WHIP make_C() – Precedence? Expression: cake = make_A() FOLD ( make_B() WHIP make_C() ) Best preparation order? A BC FOLD WHIP Evaluation order is analagous to what order you prepare A, B, and C. You can prepare A first, even though it is used last in the expression.

392 Evaluation Order [Show eval_order.] Consider: – int &f(int i) { cout << i << endl; static int x; return x; } How does this associate? – f(1) = f(2) = f(3); – f(1) = (f(2) = (f(3) = 1234)); What gets printed? Associativity does not mean evaluation order! Associativity and precedence are about grouping. – Why allow this? A few operators guarantee evaluation order. Evaluation order is not specified. – (e1) + (e2) + (e3) – If no side effects, evaluation order cannot be detected anyway. – Regardless, associativity is not the same. You could have left associative, but right-to-left evaluation order.

393 Given: – int &f(int i) { cout << i << endl; static int x; return x; } These two will print what? – f(1) = f(2) = f(3); – func(f(1), f(2), f(3)); On Linux, g++: – 1, 2, 3 and 3, 2, 1 On Linux, clang++: – 3, 2, 1 and 1, 2, 3 On Sun: – 1, 2, 3 and 1, 2, 3

394 Sequence Points What is the value of i? – int i = 0; ++i = i++ + i++; – Linux with g++: 4 – Solaris with g++: 2 – Solaris with Sun: 1 More examples: – i++ / i-- i = a[i++]; f(i++, i++) Usually only a problem when you have side effects. C/C++ defines sequence points. – All side effects are executed at sequence points. – You cannot read or write to the same lvalue multiple times between sequence points, or else you get undefined behavior.

395 What are some sequence points? – End of statement – Function call, beginning and end – Comma operator a = 1, b = 2; – Short-circuiting logical operator: && and ||

396 Casts Syntax is cast (…), but it is not a template. Syntax just kind of makes it look like one. – static_cast Used for casts that are “reasonable”, but not implicit. Like a cast from void *. Loss of precision casts. – const_cast Only used to change the const-ness of something. – dynamic_cast Cover later – reinterpret_cast Used to do things that seem to make no sense. C-style – ( T ) val T ( val ) – Anything to anything. – Precedence is very high, right after () (function call), [], ->, and. (member access).

397 const_cast can useful where you want to leverage something that returns const reference to something that you know is not actually const. – const string & shorterString(const string &, const string &); – string & shorterString(string &, string &) { return const_cast ( shorterString( const_cast (s1), const_cast (s2) ) ); }

398 Lvalues and rvalues What is an expression? Are these expressions? – 1 a a + b a * 3 + b a = c a == 3 ? c : d for (int i = 0; i < 3; i++) { j *= a; } *(ptr + 1) ptr + 4 if (a) { f(1); } sin(4) Can you categorize these expressions?

399 Hint: which of these are okay? – a = b; 1 = b; *(ptr + 1) = b; a + 1 = b; f(2) = 3; An lvalue is something that can appear on the left side of an assignment. An rvalue can only appear on the right. An lvalue has a value, but also has a memory location associated with it.

400 Constant Expressions A constant expression is a compile-time constant. Note that in general, something that is const is not necessarily a constant expression. const int i = 1; // Yes. const int i = some_func(); // No. Constant expressions can be used for array sizes, etc. But can be hard to tell. So, can use constexpr to enforce. A function can also be declared constexpr. No branches. constexpr does not need to be inline, it seems, based on tests. If the arg is const, it will be constexpr. But can return non-const if arg is not const.

401 STATEMENTS

402 Simple and Compound The simplest statement is just a ; A compound statement is enclosed in curly braces, with no terminating ; – { s1; s2; } – Often useful for short, temporary, copy-and-paste code. // Not copyable. int i =...; double x =...; //... Some statements here. // Copyable. { int i =...; double x =...; //... Some statements here. }

403 Declaration Statement Can be placed anywhere, not just at the top of a block. We call it a declaration statement, but it is usually also a definition. – extern int i; int j; What is point of declaration? – class A { int i, j, k; … }; void A::func(int i) { int ii = i; int j1 = i, j2 = j; int k = k, k2 = k; … } – ~kchiu/init.cpp

404 if Statement You can have a declaration/definition in it. – if (Obj *p = lookup(...)) { … } What does this print? – int n = -1; if (n >= 0) for (int i = 0; i < 4; i++) if (i%2 == 0) printf(“%d is even.\n“, i); else printf(“n is negative.\n"); The else is attached to the nearest if. Defensive programming: always use curly braces.

405 switch statement switch (e) { case 1: stmt1; break; case 3: stmt2; case 4: case 5: stmt3; break; default: break; // Redundant. } Integral Expression Constant label Exit switch Fall through

406 How is this code? – enum State { START, STATE1, STATE2 } state; while (not_done) { switch (state) { case START:... break; case STATE1:... break; case STATE2:... break; } }

407 Better: – enum State { START = 1, STATE1, STATE2 } state; while (not_done) { switch (state) { case START:... break; case STATE1:... break; case STATE2:... break; default: assert(false); abort(); break; } }

408 Correct: – enum State { START = 1, STATE1, STATE2 } state = START; while (not_done) { switch (state) { case START:... break; case STATE1:... break; case STATE2:... break; default: assert(false); abort(); break; } }

409 Does this compile? – switch (e) { case 1: int i = 1; // … Some code here… break; case 3: // … Some other code here… break; default: assert(false); abort(); break; } This is a jump across an initializer, and won’t compile. What’s the good practice to be learned?

410 Use blocks: – switch (e) { case 1: { int i = 1; // … Some code here… } break; case 3: { // … Some other code here… } break; default: assert(false); abort(); break; }

411 General syntax: – switch (expr) { int i; // Any sequence of any type of statements, // including further compound statements, flow // control, etc. // Case labels may be interspersed. } – switch (expr) { int i, j; if (cond) { some_statement1; case 1: some_statement2; stmnt2; } else { case 3: some_statement3; } default: some_statement4; } Show odd_switch/

412 Which is more efficient? – if (a == 900) { … } else if (a == 2) { … } else if (a == 93) { … } else { … } – switch (a) { case 900: …; break; case 2: …; break; case 93: …; break; default: …; break; } – [Show switch_jump/]

413 Which is more efficient? – if (a == 1) {... } else if (a == 2) {... } else if (a == 3) {... } else if (a == 4) {... } else if (a == 5) {... } else {... } – switch (a) { case 1: …; break; case 2: …; break; case 3: …; break; case 4: …; break; case 5: …; break; default: …; break; }

414 for Statement for (int i = 0, j = 0; j < 0; j++, i += 2) { if (some_cond) { j = 0; }... } // Search for something in a loop. for (int i = 0; i < v.size(); i++) { if (v.at(i) == what_we_are_looking_for) { break; } } How can one tell whether or not we found what we were looking for? C++11: – pos = find_if(std::begin(array), std::end(array), [&](const MyClass &o) { … });

415 for Statement for (int i = 0, j = 0; j < 0; j++, i += 2) {... } Should the i be visible after the statement? – for (int i = 0; i < n; i++) { if (…) { break; } } if (i == n) { … }

416 Range-based for (C++11): – list a_list; for (auto it : a_list) { … } – for (list ::iterator it = a_list.begin(); it != a_list.end(); ++it) { … } – int a[] = {1, 2, 3, 4}; for (int &i : a) { if (i == 3) { i++; } } – #include for (int i : {1, 2, 3, 4}) { … }

417 while Statement Can also have a declaration in it. – while (int i = j – 3) { … }

418 do - while Statement do { … } while (expr); Used for multi-statement macros. – #define m(…) \ do { \ … \ } while (false)

419 break and continue Statements break will immediately exit the nearest enclosing loop. continue will immediately re-test and possibly continue the nearest enclosing loop.

420 Can this code be simplified? – bool keep_going = true; while (keep_going) {... if (...) { keep_going = false; } else {... } } – Simplification: while (true) {... if (...) { break; }... }

421 while can be used with continue and break to create a structure like this: – while (true) { if (!try_lock(&mutex1)) { continue; } if (!try_lock(&mutex2)) { unlock(&mutex1); continue; } break; } – while (true) { if (try_lock(&mutex1)) { if (try_lock(&mutex2) { break; } unlock(&mutex1); } }

422 How about this? – do_it_again = false; do {... if (cond1) { do_it_again = true; } while (do_it_again); – while (true) {... if (cond1) { continue; } break; } I have found this style to be very useful for situations when you need to re-try something if there is some kind of error. If there is no error, you just execute once.

423 I have found that it’s often easier to write complex loops by just starting in the middle.

424 You can also use do-while to handle the previous example, but it’s not quite as elegant, at least in my opinion. – bool redo_flag = false; do { … if (cond1) { if (cond2) { … redo_flag = true; } } else { if (!cond3) { redo_flag = true; } } } while (redo_flag); –while (true) { if (cond1) { if (cond2) { continue; } } else { if (!cond3) { continue; } } break; }

425 goto Statement goto label; label: statement; Is it a good idea? How would you rewrite this? – while (expr1) { while (expr2) { if (expr3) { goto exit; } … } … } exit: Also have jump over initialization issues.

426 What about this? – again: Connection c(url); if (!c.connect()) { goto again; }

427 FUNCTIONS

428 Overview Why use functions? – It’s a way of parameterizing a piece of code. – Does slightly different things, depending on the parameters. – Does it save memory? Does it save effort? What happens when you call a function? 1.Pushes parameters on the stack (or in registers). 2.Pushes return location. 3.Makes a jump. 4.Returns a value somewhere. 5.Pops stack, jumps back. How do functions affect performance? – Some cost, but can help keep code in instruction cache.

429 Examples: – int f(int p, double, int i) { … } void f(int i, int j); What is the difference between a parameter and an argument? – int f(int p) { … } … f(1); – Parameter is what it is usually called in the function. Argument is what you pass to it.

430 Prototypes Before a function can be called, it must be declared via a prototype. – ret_type func(T1 p1, T2 p2); – Return type – Function name – Parameter list – Where should the prototype go? Does the compiler need to see it before it calls the function? Sequence of parameter types is known as the function signature. – Slightly different from some definitions of function signature, which might include the function name and return type. Declaration vs. definition – Prototype is also the declaration. Actual definition has the body.

431 Return Type ret_type foo(); Examples: – int foo(); int *foo(); MyClass foo(); int foo(); Okay? – int *foo() { int i; return &i; } int &foo() { int i; return i; } int *foo() { static int i; return &i; } int *foo() { const static int i = 2; return &i;} How do you return an array? – int foo()[] { int array[5]; return array; }

432 What does this do? – int &foo() { static int i; return i: } foo() = 3; – Since it returns a reference, a function call can act as an lvalue. It assigns to the static int inside the function. Any difference between these? – return expr; return (expr); There are three types involved. – MyType foo() { …; return val; } … ret = foo(); – There is MyType, the type of val, and the type of ret.

433 The return type can trail (C++11): – auto func(int i) -> int (*)[10]; – Trailing return types are in class scope for member functions. – class A { class B { int f(); … }; B b; … }; auto A::func(int i) -> B { … } auto A::func2() -> decltype(b.f()) { … } In C++14, the return type can be deduced: – auto odd_or_even(const int i) { if (i%2 == 1) { return “odd”; } else { return “even”; } } – In C++11, the return type of lambdas can also be deduced, but only if just a return statement.

434 Parameter List Are these the same? – int foo(); int foo(void); – int foo() {…} int foo(void) {…} Is this okay? – int foo(int i); // Prototype int foo(int j) { … } // Actual definition

435 Is this okay? – int foo(int i); // Prototype int foo(int j) { … } // Actual definition

436 Type checking/conversion – void foo(int, int); foo("a", "b"); // What happens? foo(3.14, 4); // What happens?

437 Argument Passing Semantics is initialization. – void f(int i); f(x); // Same as int i = x; – void f2(A a); f2(3); // Same as A a(3); C and C++ are pass by value. Is this efficient? – struct A { int a[1000000]; }; void f(A a);

438 Default Arguments Functions can define default arguments to be used when arguments are missing. – void foo(int i = 0); foo(1); foo(2); foo(); – void print(int v, int base=10); print(31); print(31, 10); Is this okay? – void foo(int i = 0, int j = 1, int k); foo(2, 3); No, put defaults at the end. – void foo(const char *s = “hello”, int i = 3) {} foo(5); Doesn’t work.

439 Unused arguments void f(int i, double) { … } – Why might this ever happen?

440 Ellipses void foo(const char *, …); – Need one parameter in C, but not in C++. Use.

441 Example: – #include #include void print_strings(const char *s0,...) { printf("%s\n", s0); va_list ap; va_start(ap, s0); char *s; while ((s = va_arg(ap, char *)) != 0) { printf("%s\n", s); } va_end(ap); } int main() { print_strings("string1", "string2", NULL); // Is below safe? print_strings("string1", "string2", 0); }

442 initializer_list Another way to pass a variable number of arguments. An initializer_list is a library type that the compiler creates automatically. – #include #include #include using namespace std; void func(initializer_list l) { for (auto s : l) { cout << s << endl; } } … func({“a”, “b”, “c”});

443 If different types in the list, compiler uses ambiguity resolution, trying different list types. Can overload.

444 Pointers, References, and Function Arguments Pointers or references can be used to return more than one value. – int foo(double *xp, double &y); double x, y; int ret = foo(&x, y); – Which is better? – Is there another way? Can write swap of two pointers/references like this: – void swap(int *&x, int *&y) { int *t = x; x = y; y = t; } – Java?

445 Which of f1() or f2() is better? – struct Data { int data[10000]; }; void f1(Data d); void f2(const Data &d); – Second is much more efficient, since the first will copy the data.

446 Are any of these okay? – void foo1(int &x); void foo2(const int &y); foo1(1); foo2(2); – Non-const reference requires an lvalue, so first is not okay.

447 Inline Functions Suppose we want to compute the maximum of two numbers. Where do they go? – Must go in the header file. Why? Two benefits: – Eliminating the function call overhead. – Maximizing opportunities for compiler optimizations.

448 Inline functions have external linkage, but still have to be defined in every translation unit. Need external linkage in case of static variables. Usually done as a weak symbol.

449 Function Overloading Multiple functions that share the same name can be defined. – Then how can we the compiler tell which one to call? – Why do this?

450 Overloaded Function Names Two functions with different arguments, but same names – There are some complicated rules for matching. How does the linker handle it? – [Show linking_overload.]

451 Function Signatures Overload resolution is based on function signatures, which is the parameter list. – void foo(int i); // Function 1 void foo(double x); // Function 2 void foo(const char *); // Function 3 void foo(int i, int j); // Function 4 foo(1); // Calls which? foo(1.0); // Calls which? foo("hello"); // Calls which? foo(1, 2); // Calls which?

452 Overloading Resolution When there is an exact match, it is very clear which function is called. When not, the rules are very complicated. – void foo(short s); void foo(int i, int j = 1); void foo(double x); foo(1); // Calls which? – Calls one with default parameter value. – void foo(short s); void foo(double x); foo(1); // Calls which? – Ambiguous, both are considered equally good. Overloading and scopes. Which one is called? – void f(int); void g() { void f(double); f(1); } – Name hiding, calls the inner one.

453 Basic process is: – Generate list of “viable” functions. Those are ones that have conversions that could be applied. – Then rank them in terms of preference. – If two have the same preference, then it is ambiguous, and won’t compile.

454 The rules for overload resolution from the C++ Standard.

455

456

457

458

459

460

461

462 const in Overloading Is this okay? – void f1(int i) { … } void f1(const int i) { … } – Which one would be called? Would calling the other one violate any programming language semantics? f1(1); int a; f1(a); – Would you ever use the second one? Is this okay? – void f2(int *i) { … } void f2(const int *i) { … } – Which one would be called? Would calling the other violate any programming language semantics? const int k = 1; f2(&k); int a; f2(&a);

463 Return Type in Overloading What does this do? – void foo(int); int foo(double x); … int i = foo(1); Return types are ignored, so above would be a syntax error. What about this? – void foo(int); int foo(int); – Cannot even declare them, since any call foo(1) will be ambiguous.

464 See workaround for overloading based on return type: http://stackoverflow.com/a/23473231/35217 33

465 Pointers To Overloaded Functions Pointers to functions must match exactly during assignment. – In other words, there are no conversions. – double f(int); double f(); double (*fp1)(int) = &f; // Okay? double (*fp2)(short) = &f; // Okay?

466 Uses of Function Overloading Suppose you have two functions: – void remove_node(Node *n); – void insert_node(Node *n, int position); Is this a good idea? – void doit(Node *); // Remove the node. – void doit(Node *n, int); // Insert the node.

467 Return Type Deduction In C++11, there is limited return type deduction in lambdas. – auto f = []() { return 1; } In C++14, this has been extended to non-lambdas and generalized: – auto f() { … return expr1 ; … return expr2 ; … } – All return expressions must deduce to the same type. You can have just a declaration, but can’t be called until the body is seen in the translation unit: – auto f(); … f(); // No, body not seen yet. auto f() { … } … f(); // Okay.

468 Recursion okay, but must have a non-recursive return first. – auto f() { … return f(); // No.... return 1; … return f(); // Okay. }

469 Command Line Options int main(int argc, char *argv[]) { // argv[0] is usually the command name. // argv[1] is first arg. // argc is the number of args + 1. printf(“%d, %s, %s\n”, argc, argv[0], argv[1]); } Example execution: – $./a.out foo 2,./a.out, foo

470 SCOPE AND LIFETIME (STORAGE DURATION)

471 Scope Scope is the context where a name is “visible”. Static (lexical) scope: – void foo() { int i, j; … goo(); } void goo() { int j;... i...; // Access i.... j...; // Access j. }

472 Dynamic scope: – void foo() { int i, j; … goo(); } void goo() { int j;... i...; // Access i.... j...; // Access j. } Another example: – int x = 0; int f() { return x; } int g() { int x = 1; return f(); } – What does g return if static scoping is used? What about dynamic? Returns 1 if dynamic scoping is used, 0 if lexical scoping is used.

473 Scope vs. Lifetimes Names have scope, objects have lifetimes. Your parents might call you “Sweetie Pie” at home. But when you are not at home, that name is (thankfully) out of scope. – Do you cease to exist? Scopes and lifetime are conceptually distinct, though some combinations make no sense.

474 C++ Scopes and Lifetimes Three types of scope: – Local (block) – Namespace (outermost is global) – Class Three types of lifetimes: – Automatic – Static – Dynamic

475 Global Objects How do you share an object between files? – Use global objects/functions. – Must be defined once, declared where used. // globals.h extern int var; extern double x; // defs.cpp #define extern #include "globals.h" #undef extern // file1.cpp #include "globals.h" // Use the globals. // …

476 Local Scope Function or block or statement – void func() { int i; { int i; for (int i = 0; i < 10; i++) { … } } } What is the purpose of introducing another block? Why do it? – Sometimes cleaner – Force a destructor to be called.

477 Name in local scope defines a local object. – Three kinds: Automatic (stack) Static Register Automatic – Automatic storage duration – How long is the lifetime? The end of the block. – Are they zero-initialized? No. – Is this valid? int *foo() { int i; return &i; } No.

478 Register – void foo() { register int index; for (index = 0; index < 10; index++) { // … } // … – How many have used this? – This is mainly of historical interest, most modern code doesn't use it because compilers are very good at optimizing, and usually know better than us what to put into a register.

479 Static local objects: Is this safe? – int *func() { static int i = 1; i++; return &i; } What does it return the first time it is called? Second time? We say that these have static storage duration. (Global objects also have static storage duration.) Guaranteed to be initialized to zero (or null, if it is a pointer), if not specifically initialized to something. Is it thread-safe?

480 What does this do? When is the constructor called? – int func2() { static A a(1234); // accessor1() is read-only function. return a.accessor1(); } – When is the destructor called? – Is it thread-safe?

481 Static Storage Duration Objects that have static storage duration are objects that are not necessarily marked with static keyword, but are in “permanent” storage that persists for the life of the program. Examples? – Global – Namespace – Unnamed namespace – Class static – Function static Initialization of non-local, static storage duration objects is guaranteed before main is invoked, but order between translation units is not guaranteed. – Will revisit this.

482 Linkage Linkage refers to how a name is visible during linking. External vs. internal: – External: Visible outside of the translation unit. – Internal: Not visible outside of the translation unit.

483 Linkage Directives: extern “C” Does this work? – Compiled with gcc –c foo.c : int foo() { return 1; } – Compiled with g++ -c main.cpp : int foo(); int main() { foo(); } – Link it all together: g++ -o exec foo.o main.o

484 To make a symbol link with C, need a linkage directive: – Calling C function from C++: Compiled with gcc –c foo.c : int foo() { return 1; } Compiled with g++ -c main.cpp : extern “C” int foo(); int main() { foo(); } Link it all together: g++ -o exec foo.o main.o

485 – Calling C++ function from C: Compiled with gcc –c foo.c : int foo() { return goo(); } Compiled with g++ -c goo.cpp : extern “C” int goo() {... } Link it all together: g++ -o exec main.o foo.o goo.o Can wrap a whole set of declarations. – extern “C” { // Lots of stuff can go here. }

486 Let’s say you have written a library in C, for whatever reason (maybe it runs on avionics, or embedded system, etc.). You have created a header file for it. How is this? MyHeader.h #ifndef MY_HEADER_H #define MY_HEADER_H void my_lib_func1(int); #endif main.c #include “MyHeader.h” int main() { my_lib_func1(1234); } main.cpp #include “MyHeader.h” int main() { my_lib_func1(1234); }

487 The problem is that the C++ compiler will generate mangled symbol names, to handle overloading. Need to wrap in extern “C”. How is this? MyHeader.h #ifndef MY_HEADER_H #define MY_HEADER_H extern “C” { void my_lib_func1(int); } #endif main.c #include “MyHeader.h” int main() { my_lib_func1(1234); } main.cpp #include “MyHeader.h” int main() { my_lib_func1(1234); }

488 The problem is that the C compiler doesn’t understand extern “C”. So need to use conditional compilation. MyHeader.hpp #ifndef MY_HEADER_HPP #define MY_HEADER_HPP #ifdef __cplusplus extern “C” { #endif void my_lib_func1(int); #ifdef __cplusplus } #endif #endif main.c #include “MyHeader.h” int main() { my_lib_func1(1234); } main.cpp #include “MyHeader.h” int main() { my_lib_func1(1234); }

489 const Objects Linkage Internal, unless declared extern. – // File a1.cpp. const int k1 = 3; // Not visible to other TUs. // File b1.cpp. extern const int k1; int i = k1; // Linker error. To define with extern, initialize it. – // File a2.cpp. extern const int k2 = 4; // Visible to other TUs. // File b2.cpp. extern const int k2; int i = k2; // Okay. To initialize an object with default constructor, do: – extern const A a = {};

490 Dynamically Allocated Objects Lifetime of global, local objects strictly defined. Cannot be changed dynamically. Dynamically allocated objects can be explicitly created and destroyed at runtime. Where do they come from? Where are they stored?

491 Virtual Memory A process has a range of possible memory addresses. Typically? – 0-2GB, 4G, etc. What happens when you write or read from an address? – If it is not mapped, a page fault, then OS finds some disk space for it. – Page/swap can be huge, can be many GB. 0 2 GB

492 Memory Regions Regions – Stack is used for function calls. – Heap is used for dynamically needed memory – Data is for memory that is “static”, like global variables, etc. – Text (code) is program machine code. – How about threads? – Is it all writable? Executable? Readable? What happens when you call new or malloc(), in Java or C++? Stack Invalid Heap Code (Text) Data

493 Memory allocation: first check to see if any valid, but unused. – If none available, then request more valid memory regions from OS, and use those. Key point: There are two stages of memory allocation. – First, you have to make the memory valid from the OS point of view. – Then you have to get the memory from the user-mode memory manager (typically malloc() ) – malloc() is a manager. – Why two stages? Efficiency Flexibility – What happens if you try to use the available memory without going through malloc() ? Invalid Used Available

494 How do you get memory from the OS? – In older versions of UNIX, it is a limit known as the “break”. Anything below this is valid. – Newer versions (and likely Windows) allow regions to be requested via mmap(). When you free or delete something in Java or C++, will the OS report less memory usage? – Not usually, because the user-level memory manager keeps control of it. Stack mmap’ed break

495 Implications of two-stage memory allocation: – [Interactive]

496 Question: If malloc() returns a non-null value, does it mean that the allocation succeeded?

497 malloc() and free() How do these functions work internally? How does free() know how much to free? – Allocates a bit more, uses a bit internally. – [Show malloc.]

498 Can malloc(0)? Implementation-defined free(nullptr); // Must be okay. new of 0 must be okay. delete nullptr must be okay.

499 new Use new to allocate an object (primitives are also often referred to as objects). – A *a = new A; – int *ip = new int; Is the int *ip initialized to anything? What about the object *a ? – No default initialization for *ip, but any default constructor will be called for *a. – Use this syntax to give the int a value: int *ip = new int(123); int *ip2 = new int(); Can also pass parameters to constructor: – A *a = new A(1, 2);

500 What happens if all the memory is used up? Is it a good idea to check for that? – int *ip = new int(123); if (ip == NULL) { fprintf(stderr, "Free store” “ exhausted, go home...\n"); abort(); } – Turns out that it will throw an exception.

501 delete To free memory, use delete : – A *a = new A; int *ip = new int; int *null = 0; // … delete a; delete ip; delete null; // Okay? – Standard guarantees that deleting null pointer is okay. Is the destructor called? Is the memory zero-ed out? – Should it be? – Why might we desire that the memory be zero-ed out? (Hint: Think defensive programming.)

502 Lifetime of pointer vs. lifetime of object pointed to: – int *ip; int *get() { if (ip == 0) { ip = new int; } return ip; } void free_it() { if (ip != 0) { delete ip; } } – What is the lifetime of ip ? – What is the lifetime of the object allocated? – Is it thread-safe? – How might you improve the defensive programming aspect of the above code?

503 Some delete examples. Which are errors? Which are run-time vs. compile-time? – void f() { int i; string str = "bananas"; int *pi = &i; short *ps = 0; double *pd = new double(33); delete str; // ? delete pi; // ? delete ps; // ? delete pd; // ? }

504 Arrays and New Two-dimensional arrays in C are really an array of arrays: – int a[3][4]; // How is it laid out in memory? [Show array_layout.] C arrays are row major, which means that the left one is correct. How do you compute the address of a[i][j], given a pointer to char named base ? base + i*sizeof(int [4]) + j*sizeof(int) Which dimension was not needed? 0123 4567 891011 012 345 678 91011

505 3-D arrays are similar: – int a[2][3][4]; How do you compute the address of a[i][j][k], given a pointer to char named base ? base + i*sizeof(int [3][4]) + j*sizeof(int [4]) + k*sizeof(int) Which dimension was not needed? 0123 4567 891011 12131415 16171819 2021 22 Plane 0 Plane 1 Planes Rows Columns

506 Arrays allocated like this: – int *ia = new int[10]; int (*two_d)[10] = new int[4][10]; A *a = new A[10]; – Are the arrays initialized? No. Does this work? – int (*alloc(int n))[10] { return new int[n][10]; } – Yes. How about this? – new int[n][m]; – Why not? Think of what the compiler has to do. What is the index expression? 0123 ???? ????... a[i][j] ? base + i*sizeof_of_row + j*sizeof(int)

507 Write a function to implement a 2 by 4 array from a linear 8 element array. – int *linear_array = …; int index(int row, int col) { return *(linear_array + row*n_cols + col); }

508 Arrays need to be deleted with a special syntax. – int *i_array = new int[10]; A *a_array = new A[10]; delete [] i_array; delete [] a_array; Global new and delete: – void *::operator new(size_t); void ::operator delete(void *); void *vp = operator new(10); operator delete(vp); Does this work? – struct Foo { double x; }; Foo *f = (Foo *) ::new(sizeof(Foo)); – How safe is it? What if Foo has a constructor or destructor?

509 Placement New Suppose you have two processes: – Want to share memory between them. – Want to put C++ objects in that memory. – What do you do? Suppose you are working on an embedded system. – You want to construct objects in special memory. – You know the memory begins at location 0x8000000. – What do you do? In each of these cases, you want to construct an object in special memory. – How?

510 What we want to do is to construct an object, but only at a specific location in memory. We can use placement new to do that: – SpecialObjClass *o = new (special_addr) SpecialObjClass(...); Can we delete it like this? – delete o; No, because that will try to return the memory to the free memory pool. Need to make explicit destructor call. – o->~SpecialObjClass();

511 Overloaded new and delete These can be overloaded to provide special functionality. [Show overloaded_new.]

512 Program Termination How many ways can a program exit? – Return from main(). Give integer code if not 0. – Call exit() with integer code. – Call abort().

513 Summary ScopeLifetimeLinkage Namespace Namespace, unnamed Static global Global Local, automatic Local, static New Class Class, static

514 Summary ScopeLifetimeLinkage NamespaceTranslation unitStaticExternal Namespace, unnamed Translation unitStaticInternal Static globalTranslation unitStaticInternal GlobalTranslation unitStaticExternal Local, automaticBlock Internal Local, staticBlockStaticInternal NewN/ADynamicN/A Class Same as associated object Class, staticClassStaticExternal

515 NAMESPACES

516 Name Clashes Suppose you are using someone’s library for graph algorithms. – They might have a class called Node. Suppose you want to distribute these algorithms over the network, so you also use someone’s network library. – They might also have a class called Node. Suppose you have a single implementation file (.cpp ) that needs to use both of these classes. What will happen? What is the solution? – Suppose no namespaces.

517 Namespaces The solution in the old days, before namespaces, was to use some unique prefix. – joes_graph_alg_Node *node1; janes_network_lib_Node *host; – What is the disadvantage of this? Namespaces are designed to provide a programming language means to separate and organize names.

518 The global scope is known as the global namespace scope. Within that global scope, we can define namespaces. – extern int a; namespace ns1 { extern int b; class A {…}; void f() {…} } Can be re-opened. – namespace ns1 { … } namespace ns2 { … } namespace ns1 { … } Scope resolution operator. – Outside of a namespace, you can refer to an namespace member with the :: resolution operator. namespace ns1 { int a; …} ns1::a = 1;

519 Nested namespaces – namespace ns1 { namespace ns2 { int a; } } – ns1::ns2::a = 2; Suppose you want to access a variable from several different functions (or classes). – Maybe you just want it to be accessed from functions all in a single translation unit file. – But not visible to anything outside of the translation unit. – How do you do it? Unnamed namespace – namespace { int a; } static int b; // Same effect, but deprecated.

520 Namespace aliases – namespace International_Business_Machines { int a; } namespace ibm = International_Business_Machines; ibm::a = 1;

521 Inline Namespace (C++11) An inline namespace is “absorbed” into the enclosing namespace. – Primary motivation is for versioning. – // File v2.hpp. inline namespace v2 { void foo(); } namespace v2 { … }; // Still inline. – // File v1.hpp. namespace v1 { void foo(); } – // File my_lib.hpp. namespace my_lib { #include “v2.hpp” #include “v1.hpp” } – #include int main() { my_lib::foo(1); // Picks up v2. }

522 When version 3 comes out, the inline keyword is removed from the version 2 header file and moved to the version 3 header file. – // File v3.hpp inline namespace v3 { … } – // File v2.hpp. namespace v2 { void foo(); } namespace v2 { … }; // No longer inline. – // File v1.hpp. namespace v1 { void foo(); } – // File my_lib.hpp. namespace my_lib { #include “v3.hpp” #include “v2.hpp” #include “v1.hpp” } – #include int main() { my_lib::foo(1); // Picks up v3. }

523 Using Declarations Using declarations – namespace ns1 { void f1(); void f2(); } namespace ns2 { using ns1::f2; } void func2() { f1(); // Syntax error. using ns1::f1; f1(); using ns2::f2; f2(); // Transitive. } Using declarations introduce the name at the point of the declaration, as if it had been redeclared at that point.

524 Using Directives Using directives – namespace ns1 { void some_func(); } void f1() { some_func(); // Error. } void f2() { using namespace ns1; // Okay. some_func(); } – Using directives have the effect of removing the namespaces from names, at the point where they were declared/defined in the namespace. Example: using namespace std; – Can you put a using directive in a header file? What happens if you do?

525 Suppose Jane has code like: – #include class map { … }; … lib1.hpp was written by someone else and has inside of it somewhere: – … std::map … Jane decide that there is some useful functionality in your library, so they decide to use it. You have a using namespace std directive in your header file. – #include #include class map { … }; – What would happen? – If you have using namespace std in your header file this means that merely including your header file would result in syntax errors in totally unrelated header files.

526 Using directives cannot be in class scope. Technically, the names are injected into the nearest scope that includes both the directive and the namespace being injected. – namespace ns1 { namespace ns2 { namespace ns3 { … } } namespace ns4 { // Injected into ns1. using namespace ns2::ns3; } }

527 Using directives are transitive. This can lead to ambiguity. However, qualified name lookup will cause a priority search instead. – namespace N { int i1; int i2; } namespace M { int i1; using namespace N; } namespace L { using namespace M; } int main() { using namespace L; i1 = 3; // Ambiguous. i2 = 3; // Ambiguous. L::i1; // Okay. L::i2; // Okay. }

528 namespace ns1 { int i; } namespace ns2 { using namespace ns1; int j = i; int i = 3; } int main() { using namespace ns2; i = 2; ns2::i = 1; }

529 Using Declarations vs. Using Directives Using declarations make a single name visible. Using directives make a whole namespace visible. Declarations: – namespace ns1 { void f(); } void f2() { using ns1::f; … } – As if function had been declared: void f2() { void f(); … }

530 Directives: – namespace ns1 { void f(); } void f2() { using namespace ns1; } – Same as: void f(); void f2() { … }

531 A using declaration re-declares the name as it exists at the point of re-declaration. – namespace ns { void foo(double); } using ns::foo; namespace ns { void foo(int); } int main() { foo(3); // Calls? }

532 A using directive essentially “unwraps” the namespace, even after the directive. – namespace ns { void foo(double); } using namespace ns; namespace ns { void foo(int); } int main() { foo(3); // Calls? }

533 Overloading and Namespaces When you use a using declaration, it is the same as redeclaring the name in the associated scope. – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); namespace my_lib { short max(short, short); } void func() { max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); }

534 – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); using my_lib::max; namespace my_lib { short max(short, short); } void func() { max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); }

535 – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); namespace my_lib { short max(short, short); } using my_lib::max; void func() { max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); }

536 – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); namespace my_lib { short max(short, short); } void func() { using my_lib::max; max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); }

537 – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); using namespace my_lib; namespace my_lib { short max(short, short); } void func() { max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); }

538 – namespace my_lib { int max(int, int); double max(double, double); } char max(char, char); namespace my_lib { short max(short, short); } void func() { { using namespace my_lib; max(87, 65); max(35.5, 76.6); max('J', 'L'); max(short(1), short(2)); } max(87, 65); }

539 Name Hiding and Overloading Which function does this call? – void foo(const char *); namespace ns { void foo(double x); void goo() { foo("hello"); } }

540 Scope Resolution Operator and Namespaces There are some subtle interactions: – namespace ns { void foo(int); void goo(int); void moo(int); } using ns::foo; void foo(int) {} // Syntax error. using namespace ns; void goo(int) {} // Okay. int main() { goo(1); // Syntax error, ambiguous. ::goo(1); // Okay, calls global. ::moo(1); // Okay, calls ns::moo. }

541 Another Example Consider: – namespace blip { int bi = 16, bj = 15, bk = 23; }; int bj = 0; void manip() { using namespace blip; // Clash on bj? ++bi; // ? ++bj; // ? ++::bj; // ? ++blip::bj; // ? int bk = 97; // Clash? ++bk; }

542 Consider: – namespace ns { int k; }; using namespace ns; int k; // Okay? void foo() { using ns::k; int k; // Okay? //... }

543 Linkage How is linkage of namespace members implemented? – // file1.cpp namespace A { int i; } int i; – // file2.cpp namespace A { void f() { int j = i; // Reads A::i. … } } void f() { int j = i; // Reads ::i; … } Name mangling again.

544 MULTIPLE INHERITANCE AND VIRTUAL INHERITANCE

545 Casting To and From void * Casts are dumb. – They often don’t require any machine instructions. – They just change the type of a pointer. Consider: – struct A { int i; }; struct B { char buf[10]; int i; }; A *ap = new A; ap->i = 1234; B *bp = (B *) ap; // Are bp and ap actually different addresses? cout i i << endl;

546 Consider: – class Base {… }; class Derived : public Base { … }; void foo(void *vp) { Base *bp = (Base *) vp;... } Derived *dp = new Derived; foo(dp); // Okay? – (Derived *) (void *) dp == dp; // ? Base *bp = dp; (Base *) (void *) dp == bp; // ? – [Show void_star_cast.]

547 Multiple Inheritance Do we have it in the real world? A class in C++ can inherit from multiple base classes. – Members with same name do not conflict unless they are used in an ambiguous way. An attempt to call, from the derived class, a method that is defined in both base classes would be ambiguous, for example. – Scope resolution operator ( :: ) can be used to disambiguate.

548 What functions are available at D? B1: void foo1(); B2: void foo2(); B3: void foo3(); B4: void foo4(); D: void foo5(); struct B1 { void foo1(); … }; struct B2 { void foo2(); … }; struct B3 : public B1, public B2 { void foo3(); … }; struct B4 { void foo4(); … }; struct D : public B3, public B4 { void foo5(); … };

549 What might the layout of a derived object look like in single inheritance and no polymorphism? Consider: – class A {…}; class B : public A {…}; class C : public B {…}; What is needed to upcast or downcast? What do you expect the following code print? – C c; C *cp = &c; B *bp = &c; A *ap = &c; printf(“C: %p, B: %p, A: %p\n”, (void *) cp, (void *) bp, (void *) ap); C part B part A subobject B sub- object Complete C object The A subobject begins at address 16

550 What does the layout of a derived object look like in multiple inheritance? Consider: – struct B1 { int b1; }; struct B2 { int b2; }; struct B3 : public B1, public B2 { int b3; }; struct B4 { int b4; }; struct D : public B3, public B4 { int d; }; B1 b1 B2 b2 B3 b3 B4 b4 DdDd B3 sub- object B4 sub- object B3 part: b3 B2 subobject: b2 B1 subobject: b1 B4 subobject: b4 D part: d Complete D object B1 subobject begins at address 16

551 What is needed to upcast or downcast? What does the following code print? – D d; B1 *b1p = &d; B2 *b2p = &d; B3 *b3p = &d; B4 *b4p = &d; printf(“D:%p, B1:%p, B2:%p, B3:%p, B4:%p\n”, (void *) &d, (void *) b1p, (void *) b2p, (void *) b3p, (void *) b4p) ; B1 b1 B2 b2 B3 b3 B4 b4 DdDd B3 sub- object B4 sub- object B3 part: b3 B2 subobject: b2 B1 subobject: b1 B4 subobject: b4 D part: d Complete D object B1 subobject begins at address 16

552 Revisit casting to/from void *: – D *dp = 16; void *vp = (void *) 16; (B4 *) vp ==? what address ; (B4 *) (void *) dp ==? (B4 *) dp; B1 b1 B2 b2 B3 b3 B4 b4 DdDd B3 sub- object B4 sub- object B3 part: b3 B2 subobject: b2 B1 subobject: b1 B4 subobject: b4 D part: d Complete D object B1 subobject begins at address 16

553 Example of MI: – class B1 { public: void foo() {} protected: int prot; }; class B2 { public: void bar() {} }; class D : public B1, public B2 { public: void f(); }; void D::f() { foo(); bar(); prot = 2; }

554 What order are base class constructors called? – struct B1 { B1(B2 *); … }; struct B2 { … }; class D : public B1, public B2 { … }; D::D() : B2(…), B1(this) { // Okay? … }

555 Which foo() gets called? – struct B1 { void foo(); }; struct B2 { void foo(); }; struct D : public B1, public B2 {}; D d; // Does this call B1::foo() or B2::foo()? d.foo();

556 Ambiguous or not? – class B1 { private: void foo(); }; class B2 { public: void foo(); }; struct D : public B1, public B2 {}; D d; // Does this call B1::foo() or B2::foo()? d.foo();

557 Which foo() gets called? – struct B1 { void foo(int); }; struct B2 { void foo(double); }; struct D : public B1, public B2 {}; D d; d.foo(12); // What happens?

558 Conversions to base class pointer may be ambiguous: – struct B1 { … }; struct B2 { … }; struct D : public B1, public B2 { … }; extern foo(const B1 &); extern foo(const B2 &); D d; foo(d); // What happens?

559 The ambiguity is “latent”. – struct B1 { void foo(); }; struct B2 { void foo(); }: struct D : public B1, public B2 { void goo(); }; D d; // Is this okay? d.foo(); // Is this okay? Error doesn’t happen unless/until you actually try to call an ambiguous function.

560 Resolving Ambiguities You can always use a scope resolution operator. – struct B1 { void foo(); }; struct B2 { void foo(); }: struct D : public B1, public B2 {}; D d; d.B1::foo(); But in this case, the user must know which one is correct. Better for class designer to resolve it by forwarding. – struct B1 { void foo(); }; struct B2 { void foo(); }: struct D : public B1, public B2 { // Forwarding function. void foo() { B1::foo(); } }; D d; d.foo();

561 Or use a using declaration. – struct B1 { void foo(); }; struct B2 { void foo(); }: struct D : public B1, public B2 { // Using declaration. using B1::foo; }; D d; d.foo();

562 Virtual Functions Multiple inheritance can be used with virtual functions. – The actual function called is determined by following the inheritance tree downwards from the type used in invocation. B *b = …; b->func(); // If func is virtual, follow the // tree down from B.

563 class B1 { public: virtual void foo1(); virtual void foo(); }; class B2 { public: virtual void foo2(); virtual void foo(); }; class D : public B1, public B2 { public: virtual void foo1(); virtual void foo2(); virtual void foo(); }; D d; B1 &b1(d); B2 &b2(d); b1.foo1(); // Calls ? b2.foo2(); // Calls ? b1.foo(); // Calls ? B1B2 D

564 class A1 { public: virtual void foo() = 0; }; class A2 { public: virtual void foo() = 0; }; class B1 : public A1 { public: virtual void foo(); }; class B2 : public A2 { public: virtual void foo(); }; class C : public B1, public B2 {}; C c; c.foo(); // Okay? static_cast (&c)->foo(); // Calls which foo()? static_cast (&c)->foo(); // Calls which foo()? A1: foo() = 0 C A2: foo() = 0 B1: foo() B2: foo()

565 Pure Virtual Functions (Abstract Base Class) MI can be mixed with pure virtual functions. – For a class to be instantiable, all PVFs must be defined. – class B1 { public: virtual void f1() = 0; }; class B2 { public: virtual void f2() = 0; }; class D : public B1, public B2 { public: virtual void f1() {} }; class E : public D { public: virtual void f2() {} }; D d; // Okay? E e; // Okay? B1B2 D E

566 MI with Repeated Base Class How many A subobjects in a C object? – struct A { int i_var; }; struct B1 : public A {}; struct B2 : public A {}; struct C : public B1, public B2 {}; A B1 A B2 C A subobject B1 part A subobject B1 sub- object B2 sub- object B2 part C part Complete C object Which i_var does this access? –C c; c.i_var; // Which i_var?

567 Virtual Base Classes The subobjects are different, unless the base class is virtual. – This is an overloading of the use of the term virtual. Example – class A { public: int a; }; class B1 : virtual public A {}; class B2 : virtual public A {}; class C : public B1, public B2 {}; C c; c.a; // Only one copy.

568 How many A subobjects in a C object? – class A { public: int a_member; }; class B1 : virtual public A { int b1;}; class B2 : virtual public A { int b2; }; class C : public B1, public B2 { int c; }; A B1B2 C B1 part A subobject B2 sub- object B2 part C part Complete C object No more ambiguity –C c; c.a_member; // Which a_member? B1 sub- object Diamond inheritance

569 A B1B2 C B1 part A subobject B2 sub- object B2 part C part Complete C object B1 sub- object Address 0 A B1B2 C B0 part A subobject B2 sub- object B2 part C part Complete C object B1 sub- object B0 B1 part B0 sub- object Address 0

570 [Show vb_cast.] Under virtual inheritance, a cast may be a function call.

571 Construction under Virtual Inheritance Okay? – struct A { A(const char *l) { … } }; struct B1 : public A { // Non-virtual B1() : A(“B1”) {} }; struct B2 : public A { // Non-virtual B2() : A(“B2”) {} }; – How about this? struct C : public B1, public B2 {};

572 Okay? – struct A { A(const char *l) { … } }; struct B1 : virtual public A { // Virtual B1() : A(“B1”) {} }; struct B2 : virtual public A { // Virtual B2() : A(“B2”) {} }; How about this? – struct C : public B1, public B2 {}; What parameter is passed to the constructor of A?

573 The most derived type must call the ctor: – struct A { A(const char *l) { … } }; struct B1 : virtual public A { // Virtual B1() : A(“B1”) {} }; struct B2 : virtual public A { // Virtual B2() : A(“B2”) {} }; struct C : public B1, public B2 { C() : A(“C”) {} };

574 When downcasting from VBC, need to use dynamic_cast.

575 Other Patterns Can have other different inheritance patterns: A B1B2 C A B1B2 C B3B4 AA

576 Initialization of Static-Storage Objects What are they? Static storage objects are objects that are not necessarily marked with static keyword, but are in “permanent” storage that persists for the life of the program. Examples? – Global – Namespace – Unnamed namespace – Class static – Function static

577 Are these okay? – class A { int foo(); … }; class B { B(int); … }; A a; B b(a.foo()); // Okay? extern A a2; B b2(a2.foo()); // Okay? A a2; What will happen here? – class C { C(int); int foo(); … }; extern C c1, c2; C c1(c2.foo()); C c2(c1.foo());

578 How about these? – // file1.cpp extern A a2; B b1(a2.foo()); A a1; – // file2.cpp extern A a1; B b2(a1.foo()); A a2;

579 Note that if there are no cycles, it would be plausible to require that the compiler/linker do a topological sort so that objects are always constructed before use.

580 Static Initialization vs. Dynamic Initialization Two kinds for static storage duration objects: – Static initialization: POD type, 0 or with constant. int i(123); struct A { int i, j; } A a = {1, 2}; – Dynamic initialization: All else. A a; // With ctor. int i = foo();

581 Local Objects The rule is:

582 Non-Local The rules are:

583

584 // File1 #include “a.h” #include “b.h” B b; A::A() { b.Use(); } // File3 #include “a.h” #include “b.h” extern A a; extern B b; int main() { a.Use(); b.Use(); } // File2 #include “a.h” A a;

585 The gist of it is: – The initialization order of static storage objects within a translation unit is in the order in which their definition appears in the translation unit. There is no ordering guarantee for objects in different translation units.

586 Solutions? – A &useA() { static A a; return a; }

587 Ref-qualifiers

588 Level 1: 32 pt – Level 2: 28 pt Level 3: 24 pt – Level 4: 20 pt

589 Temporaries Consider the addition operator for vectors: – Vector operator+(const Vector &v1, const Vector &v2) { return Vector(v1.x + v2.x, v1.y + v2.y); } In the expression below, how many temporaries are generated? – v = v1 + v2 + v3; Any solution?

590 Temporaries Consider this String class: – class String { public: String(const char *s = “”) : str(strdup(s.str)), size(strlen(s) { } String(const String &s) : str(strdup(s.str), size(s.size) { } ~String() { free(str); } String &operator=(const String &s) { delete [] str; str = strdup(s.str); size = s.size; } private: const char *str; size_t size; }; String s; s = “hello”;

591 Rvalue References Rvalue references bind only to temporaries. Thus, you can overload on whether or not the argument is a temporary. This allows you to steal the resources of a temporary, since it has no use for it anyway.

592 “Move” Constructors/Assignment With move functions:

593 – class String { public: String(const char *s = “”) : str(strdup(s.str)), size(strlen(s)) { } String(String &&s) : str(s.str), size(s.size) { s.str = nullptr; s.size = 0; } ~String() { free(str); } String &operator=(const String &s) { delete [] str; str = strdup(s.str); size = s.size; } String &operator=(String &&s) { swap(str, s.str); swap(size, s.size); } private: const char *str; size_t size; }; String s; s = “hello”;

594 Is an rvalue Reference an rvalue? Consider: – void foo(A &&a) { … } void foo(A &a) { … } void goo(A &&a) { foo(a); // Calls which overload? cout << a << endl; } – The type of an rvalue reference is not an rvalue reference! – The rule is that if it has a name, then it is an lvalue.

595 Move Constructors under a Base Class Consider a class with a base class: – struct Base { Base(Base &&b); // Move ctor. … }; struct Derived : public Base { Derived(Derived &&d) : Base(d) { … } … }; – Works? – struct Derived : public Base { Derived(Derived &&d) : Base(static_cast (d)) { … }

596 This is done often enough that there is a std:: function for it: – struct Base { Base(Base &&b); // Move ctor. … }; struct Derived : public Base { Derived(Derived &&d) : Base(std::move(d)) { … } … };

597 Operators Consider: – template class Vector { public: Vector(size_t sz) : (new T[sz]), size(sz) { } Vector &operator=(const Vector &v) { // Copy to data. return *this; } private: Vector(T *d, size_t sz) : data(d), size(sz) { } T *const data; const size_t size; }; template Vector operator+(const Vector &v1, const Vector &v2) { T *d = new T[v1.sz]; // Fill. return Vector (d, v1.sz); } – v1 = v2 + v3 + v4;

598 Write “move” version: – template Vector && operator+(const Vector &&v1, const Vector &v2) { for (size_t i = 0; i < v1.size; i++) { v1.data[i] += v2.data[i]; } return std::move(v1); } – v1 = v2 + v3 + v4; This requires a separate version, if, for example, v2 is the rvalue instead of v1. Need: – template auto operator+(T1 &&v1, T2 &&v2) -> decltype(std::move(v1)) { Vector &&rv(the_rvalue(v1, v2)); Vector &lv(the_lvalue(v1, v2)); for (size_t i = 0; i < v1.size; i++) { rv.data[i] += lv.data[i]; } return std::move(rv); }

599 Also consider: – template class Vector { public: Vector &operator=(const Vector &v) { // Copy to data. return *this; } private: T data[N]; }; template Vector operator+(const Vector &v1, const Vector &v2) { Vector v; // Fill v.data. return v; } – v1 = v2 + v3 + v4;

600 Example: swap [Show rvalue_swap.] Critique this: – template void swap(T &o1, T &o2) { T tmp(o1); o1 = o2; o2 = tmp; } Using std::move : – #include template void swap(T &o1, T &o2) { T tmp(std::move(o1)); o1 = std::move(o2); o2 = std::move(tmp); }

601 Forwarding What if we want to write a template as generally as possible, but also need to call some other functions: – // For non-rvalues. template void foo(const T &o) { goo(o); } – // For rvalues. template void foo(T &&o) { goo(std::move(o)); }

602 What if we gave more parameters, each of which may either be movable or not: – template void foo(const T &o1, const T &o2) { goo(o1, o2); } template void foo(T &&o1, const T &o2) { goo(std::move(o1), o2); } template void foo(const T &o1, T &&o2) { goo(o1, std::move(o2)); } template void foo(T &&o1, T &&o2) { goo(std::move(o1), std::move(o2)); } This is obviously rather unmanageable.

603 Two part solution: First, create special deduction rules for rvalue ref parameters. – template void foo(T &&o) { … } – T is A & if called on lvalue of type A. T is A if called on an rvalue of type A. T is const A & if called on const lvalue of type A. So: – A a; const A a2; foo(a); // T is A &. foo(get_an_A()); // T is A. foo(a2); // T is const A &.

604 Then, we need special rules for “collapsing” references. – If T is A &, then what is T && ? Rules are: – A& & becomes A& – A& && becomes A& – A&& && becomes A&& So, we can then write: – template void foo(T &&o1, T &&o2) { goo(static_cast (o1), static_cast (o2)); } – This is done often enough such that there is a standard function for it: std::forward. – template void foo(T &&o1, T &&o2) { goo(std::forward (o1), std::forward (o2)); }

605 RVO and move See this: http://stackoverflow.com/questions/1316607 9/move-semantics-and-pass-by-rvalue- reference-in-overloaded-arithmetic http://stackoverflow.com/questions/1316607 9/move-semantics-and-pass-by-rvalue- reference-in-overloaded-arithmetic

606 Ref Qualifiers struct A { void foo() &; void foo2() &&; }; If one overload of a function has the ref qualifier, all must have.

607 #include using namespace std; struct A { A() {} /* void foo() const { cerr << "foo() const" << endl; } void foo() { cerr << "foo()" << endl; } */ void foo() & { cerr << "foo() &" << endl; } void foo() const & { cerr << "foo() const &" << endl; } void foo() && { cerr << "foo() &&" << endl; } void foo() const && { cerr << "foo() const &&" << endl; } }; int main() { const A a; a.foo(); }

608 Pointers to Members Say that you have a class with two similar methods, op1 and op2. – class A { … void op1(); // The two are similar but not void op2(); // the same. }; Now you want to write a function to repeat any operation N times. How would you do this? – All problems in computer science can be solved with another level of indirection. – Butler Lampson

609 This suggests function pointers. How is this? – void repeat(int n_reps, void (*fp)()) { for (int i = 0; i < n_reps; i++) { (*fp)(); } } … repeat(10, &op1); // Do op1 ten times. repeat(11, &op2); // Do op2 eleven times. – How about? repeat(10, &A::op1); repeat(11, &A::op2); – Where’s the object? How about this below? – void repeat(int n_reps, A *a, void (*fp)()) { for (int i = 0; i (*fp)(); } } … repeat(10, &a, &A::op1); – More reasonable, but syntax is wrong, because a function pointer is very different from a pointer to a member.

610 Can you do this? – struct A { void f1() { … } }; void (*func_ptr)(); func_ptr = &A::f1; // Okay?

611 Pointers to member functions. Examples: – struct A { int f1(int i) { … } int f2(int i) { … } }; int (A::*fp)(int); A a; fp = &A::f1; (a.*fp)(1); // Calls A::f1(1). fp = &A::f2; (a.*fp)(1); // Calls A::f2(1). – void foo(A *ap, int (A::*fp)(int)); foo(&a, &A::f1);

612 #include class A { public: int f(int) { printf("Called A::f().\n"); } int g(int) { printf("Called A::g().\n"); } }; void func(A *ap, int (A::*ptm)(int)) { (ap->*ptm)(0); } int main() { A a; func(&a, &A::f); func(&a, &A::g); }

613 Pointer to static member function: Not associated with object, so same as regular function pointer. – struct A { static void f(); }; void (*fp)() = &A::f; Can also have pointers to data members. – struct A { int i, j; }; A a; int A::*ip; ip = &A::i; a.*ip = 1234; ip = &A::j; a.*ip = 5678;

614 A pointer-to-member of a base class can be converted to one of the derived class, but not vice versa: – struct A { void foo1(); }; struct B : public A { void foo2(); }; void (A::*ptm1)() = &B::foo2; // Error. void (B::*ptm2)() = &A::foo1; // Okay.

615 Can be a confusing when combined with static members: – struct A { void (*fp)(int); static void (*static_fp)(int); static void (*A::*static_ptm)(int); }; void (*A::*A::static_ptm)(int) = &A::fp; void (*A::*A::static_ptm)(int)(&A::fp);

616 PtM and Derivation Works under derivation: – Can apply a pointer to a base class to a derived object. (What if or private hidden member? Should still work.) – Cannot apply a pointer to a derived class to a base class object. – Can assign a pointer to a base class to a pointer to a derived class. – Cannot assign a pointer to a derived class to a pointer to a base class. You can take the address of a virtual function, and it behaves as expected: – void (Base::*fp1)(), (Base::*fp2)(); fp1 = &Base::foo1; fp2 = &Base::foo2; Derived d, *dp = &d; Base b, *bp = &b; (dp->*fp1)(); (dp->*fp2)(); (bp->*fp1)(); (bp->*fp2)();

617 PtM Example Suppose you were writing the code for the computer-controlled player in a game. – class Player { public: void fire_long_bow(); void fire_crossbow();... }; if (complicated_decision_to_use_longbow) { while (complicated_decision_to_keep_fighting) { npc->fire_long_bow(); } } else { while (complicated_decision_to_keep_fighting) { npc->fire_crossbow(); } }

618 Could make the decision once, then use a flag: – bool use_long_bow = false; if (complicated_decision_to_use_longbow) { use_long_bow = true; } while (complicated_decision_to_keep_fighting) { if (use_long_bow) { npc->fire_long_bow(); } else { npc->fire_crossbow(); } }

619 Gets messy with lots of weapons. – while (complicated_decision_to_keep_fighting) { switch (weapon_type_decided_in_code_above) { case LONG_BOW: npc->fire_long_bow(); break; case CROSSBOW: npc->fire_crossbow(); break; case SLING: npc->fire_sling(); break; default: npc->uh_oh_run_away(); }

620 Use pointer-to-member: – void (Character::*fire)(); if (complicated_decision_to_use_longbow) { fire = &Character::fire_long_bow; } else { fire = &Character::fire_crossbow; } while (complicated_decision_to_keep_fighting) { (npc->*fire)(); }

621 Another Example Node *swap = 0; Node *(Node::*child_ptm) = 0; Node *(Node::*other_child_ptm) = 0; static bool flip = false; if ((flip = !flip)) { child_ptm = &Node::left; other_child_ptm = &Node::right; } else { child_ptm = &Node::right; other_child_ptm = &Node::left; } assert((*n)->*child_ptm != 0); swap = (*n)->*child_ptm; while (swap->*other_child_ptm != 0) { swap = swap->*other_child_ptm; }

622 TEMPLATES

623 Introduction How is a template different from normal source code? – void foo() {…} template void foo1() {…} – Template definitions are not really “compiled”. Just cause things to be remembered.

624 Templates Are Like Super Macros Where do you put templates, header files or implementation files? – Every use must be preceded in the same translation unit by its definition. – Private template could be in an implementation file.

625 A template is just that, a template or “pattern”. – Essentially a macro on steroids. Normal source code is compiled on a one-to-one basis. void f(int i) { … } f: save_regs ld r0, sp(0) add ret One function in source code One function assembly language Compilation

626 A single template serves as a pattern, so it can be used multiple times to create multiple “instantiations”. template void f(T i) {… } f: save_regs ld r0, sp(0) add 4 ret One function in source code Multiple functions in assembly language Compilation & instantiation f: save_regs ld r0, sp(4) add 8 ret f: save_regs ld r0, sp(8) add 16 ret

627 template void f(T i) {…} f : save_regs ld r0, sp(0) add 4 ret Instantiation f : save_regs ld r0, sp(4) add 8 ret f : save_regs ld r0, sp(8) add 16 ret void f(char i) {…} void f(double i) {…} void f(int i) {…} Compilation

628 What happens when compiler encounters a normal function definition? A template definition? – void foo() {…} // Normal function. template void foo1() {…} – Template definitions are not directly “compiled” when encountered by the compiler. Just cause things to be remembered, for later instantiation.

629 Templates and Classes as Models Both are “models”. (What is a model?) – Classes are models for objects. An object: Has source code (member functions). Has data (member variables). But source code never differs. Data layout never differs. Only the values differ. – Templates go back one step. They are models for classes or code. You first instantiate a template to fix a particular source code and data layout. The source code of different instantiations can differ. The data layout of different instantiations can differ. Sometimes known as parametric polymorphism (compared to subtype polymorphism).

630 Example Suppose you want to define a function to find the minimum of two integers: – int min(int i1, int i2) { return i1 < i2 ? i1 : i2; } Now how about for doubles: – double min(double x1, double x2) { return x1 < x2 ? x1 : x2; } Now how about long longs… – Solution?

631 Could use a macro: – #define min(x, y) \ ((x) < (y) ? (x) : (y)) Disadvantages? – Side effects, due to double evaluation. – Hard to debug, especially for multiline. – Code bloat, since they are inherently inlined.

632 Function template: – template // Same as “template ” T min(T v1, T v2) { return (v1 < v2) ? v1 : v2; } – Is this right? g++ standard library definition: – template inline const _Tp& min(const _Tp& __a, const _Tp& __b) { if (__b < __a) return __b; return __a; } – Why the underscores?

633 Why do we have parentheses around the parameters? – #define min(x, y) \ ( ( x ) < ( y ) ? ( x ) : ( y ) ) Because substitution is purely lexical. Without parentheses, it would be translated as: – #define min(a, b) (a < b ? a : b) min(x & 0xff, y) (x & 0xff < y ? x & 0xff : y) Translated to abab

634 Do we need to do the same thing with templates? – template inline const T& min(const T& a, const T& b) { if ((b) < (a)) return (b); return (a); } – min(x & 0xff, y) No, because template instantiation is not lexical. – In some sense, you could say that the compiler inserts the parentheses for you.

635 Four Kinds Alias templates – Patterns for type aliases (typedefs). – template using ptr = T *; ptr ip; // ip is a pointer to an int. Function templates – “Patterns” for free-standing functions – template void f(const T1 &o1, const T2 &o2) { … } Class templates – “Patterns” for an entire class, including member functions and member variables. – template class A { … };

636 Member templates – “Patterns” for a single member function inside a class (which may or may not be a templated class). – struct A { template void f(const T1 &) {…} … };

637 Template Parameters Each template has a list of template parameters. When the template is actually used, the parameters are filled in with real things, and an actual function or class is generated. This is known as an instantiation. – template void func(); In normal functions, each parameter is replaced with a value (of a specific type). – void print_int(int i) { cout << i; } In templates, each parameter is replaced with a type, or a constant (for non-type parameters). – template void print(T o) { cout << o; } – After instantiation, it is a function: void print (MyClass o) { cout << o; }

638 In normal functions, the argument to the parameter is specified explicitly in the argument list. – void foo(int p1, double p2, const char *p3); foo(123, x, “hello”); For template parameters, the replacement can be specified explicitly, as in functions, or they can be deduced. – template void f(T1, T2); f(123, 3.14); f (123, 3.14);

639 Inside a template, a template type parameter works just like any C++ type. – template void f(T v) { T temp; } A non-type parameter works like a constant value. – template void f() { int i = N; printf(“%d\n”, N); } The type parameter can be used as any other type: – struct A { typedef int foo; struct N { … }; }; template void func(T v) { typename T::foo i; // Define an int. typename T::N n; // Define an N object. … }

640 As with normal functions, the name of a template parameter can be reused. – void f(int i) { … } // Reusing i is fine. void f2(int i) { … } template void func() { … } // Reusing T is fine. template void func2() { … } As with normal functions, you can’t reuse the name within a single template, though. – // Error. template void func3() { … }

641 Non-Type Parameters These look like ordinary parameter declarations, but must be instantiated with a constant value. – template … Why might this be useful? – template void sort(T (&a)[N]) { T save[N]; if (1 < N) {…} } – Will the if stay in the compiled code?

642 Another example: – template void msg(const char *m) { cerr ; extern const char error_s[] = "Error"; void (&error)(const char *) = msg ; int main() { warn("Danger, Will Robinson!"); error("That does not compute."); }

643 #include using namespace std; template struct A { void doit(int i) { cout << F(i) << endl; } }; inline int foo(int i) { return i + 1234; } void some_func(int i) { A a; a.doit(i); } It does get inlined properly.

644 Example of how PTM non-type param might be useful template class List { private: struct Link { Link *next, *prev; }; template class Iterator_tmpl { public: Iterator_tmpl &operator++() { m_link = m_link->*advance; return *this; } private: Link *m_link; }; public: using Iterator = Iterator_tmpl ; using ReverseIterator = Iterator_tmpl ; Iterator begin() { return Iterator(); } ReverseIterator rbegin() { return ReverseIterator(); } }; int main() { List l; List ::Iterator it = l.begin(); ++it; List ::ReverseIterator rit = l.rbegin(); ++rit; }

645 ALIAS TEMPLATES

646 template using ptr = T *; ptr p; // Defines a pointer to an int. – template typedef T *ptr; // Syntax error. template using my_map_t = std::map >; my_map_t m1; my_map_t m2;

647 FUNCTION TEMPLATES

648 Function templates are “patterns” for freestanding functions. – Allow a function to be parameterized by type. The syntax is: – template void f(…) { … } Inside the function body, and in the parameter list, you can use T1, etc. Example: – template T1 f(const T2 &p1, const T2 p2, T2 (*fp)(T1)) { T1 t1; T2 t2; … return t1; } Can be used multiple times.

649 More examples: – template const T &min(const T &a, const T &b) { return a < b ? a : b; } – i = min(j, k); std::string first, s1(…), s2(…); first = min(s1, s2);

650 Another example: – template T min(T (&array)[size]) { T m = array[0]; for (int i = 1; i < size; i++) { if (array[i] < m) { m = array[i]; } } return m; } Will the above work for all classes? If not, how can it be improved? – template const T &min(T (&array)[size]) { int min_index = 0; for (int i = 1; i < size; i++) { if (array[i] < array[min_index]) { min_index = i; } } return array[min_index] }

651 Template Parameters Template parameter hides global. – int T; template void foo() { … T … } // Refers to template parameter. Cannot define object with same name. – template void foo() { int T; // Error. } Can be used to specify the return type. – template T foo() { … } Cannot be used twice in one declaration or definition. – template void foo() { … }

652 Can be reused across definitions. – template void foo() { … } template void func() { … } Can change across declarations/definitions. – template void foo(T t); template void foo(U u); template void foo(V v) { … }

653 Instantiation Instantiation is the process of actually filling in the template parameters, and constructing the actual function. Occurs implicitly either when a function is called, or when a function address is taken. – template void foo(T) {…} foo(1); void (*fp)(double) = &foo; During instantiation, the template parameters must be bound to actual template arguments, during a process know as template argument deduction. – Compile time or run time?

654 Template Argument Deduction Deduction is more complicated than a simple replacement. (But luckily the compiler does it.) – template sort(MyList &a); MyList a1; MyList a2; sort(a1); // What is T? sort(a2); // What is T? – template void func_tmpl1(T (*f)(int)); double f1(int); func_tmpl1(&f1); // What is T?

655 – template void func_tmpl2(int (*fp)(T)); int f1(double); int f2(char *); double f3(double); func_tmpl2(f1); // What is T? func_tmpl2(f2); // What is T? func_tmpl2(f3); // What is T? – template void func_tmpl3(T1 (*fp)(T2)); int f1(double); double f2(char *); func_tmpl3(f1); // What is T1, T2? func_tmpl3(f2); // What is T1, T2?

656 Do these compile? – template const T &min(const T &, const T &); … min(1, 3.14); min(1, 2U); – template T min2(T *, int size); … int a[4] = {1, 2, 3, 4}; min2(a, 4); – template T min3(const T *, int size); … min3(a, 4);

657 How about these? – template void func(T *p1, T *p2); class A {…}; class B : public A {…}; A a; B b; func(&a, &b); // Okay? func(&a, static_cast (&b)); // Okay? – template void func(Container &); template class FancyContainer : public Container { … }; FancyContainer fc; func(fc);

658 – template void func(T *, T *); template class B {}; class D : public B {}; B b; D d; func(&b, &d);

659 Arrays are converted if the parameter is not a reference: – template void foo(T1 p1, T2 &p2) { … } … int a[10]; foo(a, a); – T1 is deduced to be int *, but T2 is deduced to be int [10].

660 Most conversions are not applied for template argument deduction. Only conversions that are used are: 1.Lvalue to rvalue, such as array to pointer. template void f(T *); int a[] = {1, 2}; f(a); Unless the parameter T is a reference! 2.Qualification conversion, such as adding const. template void f(const T *); double x; f(&x); 3.Derived pointer or reference to base class pointer or reference, if the classes are class templates. template void f(A *); template class B : public A { … }; B b; f(&b);

661 Note that even though usual conversions are not applied to template arguments, they are applied to non-template arguments. – template void func(T v1, T v2); func(1, 1.23); // Okay? – template void func2(T v1, double v2); func2(1, 123); // Okay? Remember, there are two steps: 1.Template argument deduction 2.Overload resolution. Template deduction happens first!

662 The return type of the function template is not deduced. (Also not used for overload resolution.) – template T f(); int i = f(); // Okay? – template T f2(T *); double x = f2((int *) 0); // Okay? – template T f3(T); double x = f3(1); // Okay? template T f4(T, T); double x = f4(1, 1.3); // Okay? Note that the return type of a function in a parameter is deduced, however.

663 Non-deduced Contexts template struct Outer { struct Inner { T var = 0; }; // Specialization. template <> struct Outer { // Type alias. using Inner = typename Outer ::Inner; }; template void foo(const typename Outer ::Inner &) { } int main() { Outer ::Inner i1; Outer ::Inner i2; // Line below is fine, they really are the same type. i1 = i2; foo (i1); // This is fine. foo (i2); // This is fine. foo(i1); // Error, can't deduce T, because it's both int and double! }

664 template class Outer; template void func(const typename Outer ::Nested &) { } template struct Outer { struct Nested {}; friend void func2(const Nested &o) { func (o); } }; int main() { Outer ::Nested o; func (o); // Okay. func(o); // Fails when uncommented. func2(o); // Okay, uses Barton-Nackman trick. }

665 Deduction procedure is as follows: 1.Each function parameter is examined to see if it includes a template parameter. 2.If so, a match is attempted, normal conversions are not used on template arguments. They are used on non- template arguments. 3.If a template parameter is in more than one function parameter, then the deduced template argument must be the same in each function parameter. There are lots of complicated rules. Usually you only need to look into them when the compiler does the “wrong” thing: – It thinks the situation is ambiguous, but you don’t. – It deduces arguments differently from what you think it should.

666 Explicit Arguments Most of the time, you want the compiler to deduce the arguments. – template T min(T v1, T v2); min(1, 2); min(1, 3.14); // Okay? – template T f(); int i = f(); // Okay? Solution is to use explicit arguments – min (1, 3.14); min (1, 3.14); int j = f (); // Okay?

667 Suppose we have a function sum(), what should we use for the return type? – template T1 sum(T1, T2); short s; sum(s, 1); sum(1, s); // Okay? – template T2 sum(T1, T2); short s; sum(s, 1); sum(1, s); // Okay? No good options in C++98. Any choice will not work, so the solution is to use an explicit argument. – template RT sum(T1, T2); sum (s, 1); sum (1, s);

668 If using C++11, we can use decltype. – template auto sum(T1 v1, T2 v2) -> decltype(v1 + v2); sum(s, 1); sum(1, s); Possible without trailing return type, but ugly: – template decltype(*(T1 *) nullptr + *(T2 *) nullptr) sum(T1 v1, T2 v2); sum(s, 1); sum(1, s); – template decltype(std::declval(T1) + std::declval(T2)) sum(T1 v1, T2 v2);

669 Instantiation, and template argument deduction also happens when the address of a function is taken. What happens here? – template const T &min(T (&arr)[size]) { … } typedef int (&array_int)[10]; typedef double (&array_double)[20]; void func(int &(*)(array_int)); void func(double &(*)(array_double)); … func(&min); To solve: – func(static_cast (&min)); func(&min );

670 Specialization Consider: – template T min(T a, T b) { return (a < b) ? a : b; } What happens when you call? – min(“a”, “b”) Sometimes, the generic definition of a template is not right. Explicit specializations can then be used. – template <> const char * min (const char *s1, const char *s2) { return strcmp(s1, s2) < 0 ? s1 : s2; }

671 Does this work? – template T min(T a, T b) { return (a const char * min (const char *s1, const char *s2) { return strcmp(s1, s2) < 0 ? s1 : s2; }

672 At least declaration must be seen first. – template T min(T a, T b) { return (a const char * min (const char *s1, const char *s2); int main() { const char *first = min(“a”, “b”); } template <> const char * min (const char *s1, const char *s2) { return strcmp(s1, s2) < 0 ? s1 : s2; } Must be seen by all translation units. Where do specializations go? In header files or in.cpp files? – They go in.cpp files, because they are actually compiled.

673 Template arguments can be omitted if can be deduced. – template T min(T a, T b) { return (a // const char * // min (const char *s1, // const char *s2); template <> const char * min(const char *s1, const char *s2);

674 Overloaded Templates Multiple templates can exist for a single function name. – template void func(Array ) {…} template void func(List ) {…} List l; Array a; func(l); func(a);

675 There can be more than one match: – template void func(T *p) { … } // V1 template void func(T o) { … }; // V2 char *p; func(1); // Okay? func(p); // Okay? Which version? – The most specialized version is chosen. Sometimes still ambiguous. What counts as more specialized? – Accepts fewer matches. If something matches V1, will it match V2? What about vice versa? Which version accepts fewer matches? – Must have same number of template parameters.

676 Can lead to ambiguity. Suppose we start with this: – template int min(T, T) { … } min(1, 2); // Okay? min(1, 2U); // Okay? We then try this: – template int min(T, T) { … } template int min(T1, T2) { … } min(1, 2U); // Okay? min(1, 2); // Okay?

677 Show array and: foo(T *o); foo(T (&a)[N]); Ambigu but not: foo(T o); foo(T (&a)[N]); // Okay due to partial ordering rules.

678 Template Mixed with Nontemplate Is this valid? – template T sum(T, int); template T sum(T, double); double sum(double, double); Which one gets called? – sum(3.14, 3.14); – sum(3.14, 1); – sum(1, 3.14);

679 What is the advantage of a non-template over a specialization? – The advantage is that you skip the argument deduction phase, so you avoid some ambiguity traps. Suppose you have a special version of min() that you want to be called for all integer types, such as short, etc. – // Generic definition. template T min(T v1, T v2) { … } // Specialization template <> int min (int v1, int v2) { … } int i =...; short s =...; min(i, s); // Which does this call? Can use non-template to enable more conversions. – // Normal conversions will be used. inline int min(int v1, int v2) { return min (v1, v2); } – min(i, s); min(s, s);

680 Summary of Resolution For a given invocation: – min(…); The steps are: 1.For each template, try to deduce arguments. If success, add the template to the overload list. Deduction failure by itself is not an error. 2.Add all non-templated functions to the overload list. 3.Use normal overload resolution. Prefer non-templated. If a specialization is selected, don’t instantiate.

681 Specialization Revisited Recall: The default option should be to pass arguments by const reference. – template const T &min(const T &a, const T &b) { return (a < b) ? a : b; } We also need the specialization for strings: – template <> const char * min(const char *s1, const char *s2) { return strcmp(s1, s2) < 0 ? s1 : s2; } – Okay?

682 Need same form. Okay: – template const T &min(const T &a, const T &b) { return (a < b) ? a : b; } – template <> const char *const & min(const char *const &s1, const char *const &s2) { return strcmp(s1, s2) < 0 ? s1 : s2; } – Okay now?

683 Solution? – const char * min(const char *, const char *); – template const T * min(const T (&a1)[N1], const T (&a2)[N2]);

684 Namespaces and Function Templates Namespaces and function templates interact as expected. For example, a specialization can be defined by: – namespace ns1 { template const T &min(const T &v1, const T &v2) { … } } … // Can reopen it. namespace ns1 { template <> const myns::MyInt & min(const myns::MyInt &i1, const myns::MyInt &i2) { … } } // Or can use namespace syntax. template <> const MyInt & ns1::min(const MyInt &i1, const MyInt &i2) { … }

685 CLASS TEMPLATES

686 Class templates are “patterns” for classes. – Allow a class to be parameterized by type. The syntax is: – template class A …; – T1 and T2 can be used anywhere.

687 Example: – template class A : public Base { public: T2 member_func(T1); private: T1 data_member; T2 data_member; T1 a[N]; }; – Type parameters can be used anywhere a type would normally be. – A constant int parameter can replace any constant int. Type parameter Int (non-type) parameter Type parameter used for derivation Non-type parameter use

688 Member functions are defined with: – template class A { … }; template void A ::func() { T obj; int i = N; }

689 Another example: – template class Array { T a[N]; T operator[](int i) { return a[i]; } }; What is the syntax to define an object using this template? – Array a; How might you improve this? – Add range check – Allow the index operator to be used as an lvalue by returning a reference – Adding a const version to be used with const arrays.

690 Template Parameters Can have multiple ones: – template class A; – typename or class are the same. You can actually replace class with a fundamental type. template class B; B a; // T is bound to int.

691 Inside a template, the name of the class refers to the parameterized name. – template struct Buffer { … Buffer *next; // Same as Buffer. }; Is this okay? – Buffer b1; Buffer b2; b1.next = &b2; // Okay?

692 Template parameters hide other names: – typedef double T1; template class A { T1 something; }; Template parameters will clash with names of members: – template class A { double T1; // Error. }; Reuse of a template parameter name within the same template is an error. – template // Error. class A; Can be reused across templates, though. – template class A; template class B;

693 Template parameter names are just placeholders. As such, they can change with no effect. – template class A; template class A; template class A; template class A { … };

694 Template parameters can have default arguments. (In C++11, also function templates.) – template > class Stack { private: Container_T elems; … }; Default arguments can be redefined. – template class Buffer; Buffer buf; // Size is 1024. template class Buffer; Buffer buf2; // Size is 2048.

695 Instantiation A class template is used by giving the template name plus the parameters. – template class A { … }; … A a; There is no template argument deduction for class templates. – template struct A { A(T); … }; A a(1234); // Error, does not create an A.

696 When you write: – Stack s; The instantiation is this: class Stack { private: std::vector elems; public: void push(const int &); void pop(); int top() const; }; void Stack ::push( const int &o) { elems.push_back(o); } template class Stack { private: std::vector elems; public: void push(const T &); void pop(); T top() const; }; template void Stack ::push(const T &o) { elems.push_back(o); } …

697 An instantiated class template can be used anywhere that a non-template class can be used. – If you can write MyClass, you can write MyTemplatedClass. Instantiated only when used in a context that requires definition to exist. Does this compile? Is it an instantiation? – template class A; void foo(A &); – Not instantiation. How about this? – void foo(A &a) { a.foo(); } – Yes, it is an instantiation. Different instantiations are completely independent.

698 What is the difference between Queue and Queue in the following? – template void bar(Queue &, Queue &); – Outside of a template definition, can only use instantiations.

699 Is this an instantiation? – int foo(Queue *p) { } How about this? – int foo(Queue *p) { return p->doit(); }

700 Member functions, recall, are defined with this syntax: – template class A; template void A ::foo() { … } Not instantiated till called or address taken. So, no need for definition unless called.

701 Example Interactive

702 Example Example of a class template for a stack. – template class Stack { private: std::vector elems; public: void push(const T &); void pop(); const T &top() const; }; template void Stack ::push(const T &o) { elems.push_back(o); } template void Stack ::pop() { elems.pop_back(); } template T &Stack ::top() const { return elems.back(); }

703 A Template Idiom Is this okay? – class A : public Tmpl { … }; Does it cause infinite recursion? – template class Tmpl { T *ptr; }; – template class Tmpl { T t; }; – [Show crtp/] Occurs often enough so that it is sometimes referred to as the curiously recurring template pattern (CRTP).

704 Function Templates Interacting with Class Templates Consider: – // Function 1 template void foo(const T &) {... } // Function 2 template <> void foo(const int &) {... } // Function 3 void foo(const int &) {... } What is Function 2? Function 3? How can I call Function 1? 2? 3? – foo(3.14); – foo<>(1); – foo(1);

705 Consider: – template class A {... }; // Function 1 template void foo(const A &) {... } // Function 2 template <> void foo(const A &) {... } // Function 3 void foo(const A &) {... } What is Function 2? Function 3? How can I call Function 1? 2? 3? – A a_double; A a_int; – foo(a_double); – foo<>(a_int); – foo(a_int);

706 Friends A friend can be defined in a number of ways. – class A { template friend void f(); friend class B ; … }; template class B { friend class C ; template friend class D; … };

707 Does this work? – template class A; template int foo(A &o) { return o.private_member; } template class A { friend int foo(A &); int private_member; }; No. A function template is not the same as a non-templated function. – template int foo(T &o) { return o.private_member; } class A { friend int foo<>(A &); int private_member; };

708 Friends defined inside a class template.

709 Static Data Members A template class can have static data members. – template class A { static T static_member; }; template T A ::static_member;

710 Nested Types of Class Templates A class template can have a nested class. – template class A { class Buffer { T *data; }; }; Can only be accessed with instantiation. – A::Buffer; // Error. – A ::Buffer; // Okay.

711 typename keyword Consider – template void foo(const T &) { T::name *p; } – Is this a syntax error? What if T is? – struct A1 { static int name; }; foo(A1()); – struct A2 { typedef int name; }; foo(A2()); – Can’t tell without knowing details of T. Use typename keyword – template void foo(T) { typename T::name *p; }

712 Specialization As with function templates, class templates can be specialized for a particular set of template arguments. – template <> class A { … };

713 Specialization of Stack class: – template <> class Stack { private: std::deque elems; public: void push(const std::string &); void pop(); const std::string &top() const; }; void Stack ::push(const std::string &o) { elems.push_back(o); } void Stack ::pop() { elems.pop_back(); } std::string &Stack ::top() const { return elems.back(); }

714 The specialization can be completely different. – template class Stack { private: std::vector elems; public: void push(const T &); void pop(); T top() const; }; // Specialization template <> class Stack { private: char a[10]; public: double foogoo(); };

715 Nothing is anything carried over from the generic implementation. – template struct A { void generic_foo(T *) { … } … }; template <> struct A { … }; … A a; // Implemented in generic template, okay? a.generic_foo(); Why not? – What if generic_foo() uses member variables? Are they present in the specialized class template?

716 You can also specialize member functions individually: – template class A { T foo() { … } // Generic impl. }; // Specialization. template <> double A ::foo() {…} Where do these go, header or program text? – Go in.cpp file, because they are not templates. – Must place a declaration before point of instantiation.

717 Partial Specialization In a full specialization, all template parameters are filled in. In a partial specialization, some template parameters are filled in. – template class MyClass {…}; template class MyClass {…};

718 Or, the template parameters can just be more specific. – template // 1 class MyClass {…}; template // 2 class MyClass {…}; template // 3 class Myclass {…}; MyClass obj1; MyClass obj2; MyClass obj3; MyClass obj4;

719 Further examples: – template class A { … }; template class A { … }; A bit poorly named: – Full specialization: All parameters filled in. – Partial specialization: Some parameters filled in, at least one left free. DOES NOT MEAN: Some aspects specialized, others left as is. – As with full specialization, nothing is carried over from the unspecialized template.

720 Partial Specialization vs. Overloaded Function Templates Function templates cannot be partially specialized, but can be overloaded. Class templates cannot be overloaded, but can be partially specialized. Usually, the distinction is not crucial.

721 Usually, the distinction is not crucial: – template void foo(T1, T2); template void foo (T1, int); // No. template void foo(T1, int); // Okay. template void foo(T1 *, T2); // Okay.

722 – template class A {... }; template class A {... }; // No template class A {... }; // Okay. template class A {... }; // Okay.

723 Namespaces and Class Templates

724 MEMBER TEMPLATES

725 Member Templates Suppose we had a class that represented an output stream. We wanted it to be able to print out any object, but with an ID in front of it. – class Output { public: void print(int v) { os << id << “: “ << v << endl; } void print(double v) { os << id << “: “ << v << endl; } void print(const A &obj) { os << id << “: “ << obj << endl; } … }; What if we add a new class named B? Is there any way we can avoid duplicating all this code?

726 We can use a member template. A member template is a template for a single member of a class. – class Output { public: template void print(const T &v) { os << id << “: “ << v << endl; } … }; Member templates can also be classes: – class Output { template class Helper { … }; … };

727 Three possibilities: – class Output { template class Helper { … }; … }; – template class Output { class Helper { … }; … }; – template class Output { template class Helper { … }; … };

728 To define a member template outside of a class, use this syntax: – class Output { public: template class Helper; template void print(const T &v); … }; template class Output::Helper { … }; template void Output::print(const T &v) { os << id << “: “ << v << endl; }

729 If the outer class is also a template, the syntax for defining outside of the class is: – template class A { public: template class Helper; template void foo(const U &); … }; template template class A ::Helper { … }; template template void A ::foo(const U &u) { … }

730 Operators can also be member templates: – class A { template void operator+(const T &); }; – A a; a + 2; // Calls template.

731 Special Member Templates Let’s say you have an array type, named Array. Since it’s a container, you make it templated. – template class Array { … }; What is the relationship between Array and Array ? – Array int_array; Array short_array; … int_array = short_array; // Okay? // Okay? Array int_array2(short_array);

732 Let’s say that someone else is using your Array class. She has a class A and B, and has provided conversion and assignment operators in both directions A  B. – A a(…); B b(…); A a1(b); B b1(a); a1 = b1; b = a; What is the situation between Array and Array ? – Array a_array; Array b_array; … a_array = b_array; // Okay? Array a_array2(b_array); // Okay?

733 Solution is templated constructors and/or assignment operators. – template class Array { public: template Array(const Array &a) {... // Do allocation, etc. for (int i = 0; i data[i] = a.data[i]; } } }; Let’s say there is no conversion between the types C and D. – Array c_array; … Array d_array(c_array); // Okay? – Where in the source code above does the error occur?

734 Consider: – template class A { public: A(int); template A(const A &o); private:... }; What constructor is used to construct a2? – A a1(2134); A a2(a1); A a3(a2); Template copy constructors do not inhibit generation of implicit copy constructor. – Even deleting them doesn’t help.

735 Conversion operators can also be templates: – class A { public: template operator T(); }; struct B { }; struct C { C(int); };... A a; (int) a; // Uses the conversion operator. int i = a; // Okay? B b(a); // Okay? C c(a); // Okay?

736 Member templates can have explicit arguments: – class A { public: template void foo(); template A(); }; – A a; a.foo (); // Okay? A a2 ; // Okay?

737 One solution: – class A { public: template A(T *); }; How do you invoke the constructor? – A a((T *) 0); Disadvantages? – Might conflict with an actual constructor that takes pointers.

738 A better solution: – class A { public: template A(tag ); }; How do you invoke the constructor? – A a(tag ()); How is tag defined? – template struct tag {};

739 Virtual Member Templates Can member templates be virtual? – class A { public: template virtual void foo(); … }; class B : public A { public: template virtual void foo(); … };

740 No, because instantiation is problematic. – class A { public: template virtual void foo(); … }; class B : public A { public: template virtual void foo(); … }; – void foo(A &a) { a.foo (); // What is a? }

741 Summary Member function templates: – They behave much like normal function templates. – Template argument deduction? – Specialization? Member class templates: – They behave much like normal class templates. – Can have specializations and partial specializations.

742 ADVANCED TOPICS

743 Context Free or Context Sensitive? Intuitively, what is a context free language? – It means that when you see something, it knows exactly what it means, without context. – Is English context-free? "He ate the cookies on the couch." "He gave her cat food."

744 Consider this CFG: – Expr  Expr + Expr Expr  Expr * Expr Expr  VarName Expr  Integer – How would you parse? a + b * 1234 What mechanisms/techniques are used to parse most computer languages?

745 Parsing: – x * y; // What does this mean? – X (0); // What does this mean? 2: template struct X { X(int); }; 1: int X=2; 1: int x=2; 2: typedef int x;

746 Parsing: – x * y; // What does this mean? – X (0); // What does this mean? Is this a contradiction? Are most languages context- sensitive then? Why do we usually not care about this? – Usually the correct interpretation is obvious, because we don’t have to consider both choices being possible. – With the templates, the different interpretations become more important. 2: template struct X { X(int); }; 1: int X=2; 1: int x=2; 2: typedef int x;

747 Template Template Parameters Let’s say that we want to make a stack container. It may contain different type of objects. So we make it a template. template class Stack { private: std::vector elems; public: void push(const T &); void pop(); T top() const; }; template void Stack ::push(const T &o) { elems.push_back(o); } template void Stack ::pop() { elems.pop_back(); } template T Stack ::top() const { return elems.back(); }

748 This version is based on a vector. Suppose sometimes we want to use a vector, but other times we want to use a list. – Or maybe we want to let the user plug-in her own underlying container type. – How to handle? – Standard approach is to use polymorphism. (A member function template can’t be virtual, but a class template can have virtual functions.) template class Stack { private: std::vector elems; public: void push(const T &); void pop(); T top() const; }; template void Stack ::push(const T &o) { elems.push_back(o); } template void Stack ::pop() { elems.pop_back(); } template T Stack ::top() const { return elems.back(); }

749 User does: – Stack stack(new MyContainer ); Possible disadvantages of this method? Can I use it with std::vector? – Intrusive (requires modifying the container templates), possibly not so efficient, prevents use of member templates. template class Stack { private: Container *elems; public: void push(const T &); void pop(); T top() const; }; template void Stack ::push(const T &o) { elems->push_back(o); } template void Stack ::pop() { elems->pop_back(); } template T Stack ::top() { return elems->back(); }

750 Use another template parameter. template class Stack { private: C elems; public: void push(const T &); void pop(); T top() const; }; template void Stack ::push(const T &o) { elems.push_back(o); } … Stack > stack; Not that bad in this simple example, but you might want to use a vector of ints and a vector of int * in a single class, for example.

751 No way to use this to create two different containers with different type parameters. template class SomeClass { private: C something; // Contains ints. C something_else; // Contains int *. }; SomeClass > obj;

752 Instead, can use something known as a template template parameter. A normal template parameter says: I don’t know what the type of this is yet. A template template parameter says: I don’t know what the type of this is yet, but it will be a (uninstantiated) template. template class CONT> class Stack { private: CONT elems; … }; template class CONT> void Stack ::push(const T &o) { elems.push_back(o); } … Stack s; // Not Stack >

753 Does this compile? template class A { … }; template class CT> class B { … }; … B b; No. –Because the class template A has two template parameters, but the template template parameter in B has only one template parameter.

754 If you try to use this with the standard C++ containers, it will fail. template class CONT> class Stack { private: CONT elems; public: void push(const T &); void pop(); T top() const; }; … Stack stack; // Syntax error! Why? –Hint: How many template parameters does std::vector have?

755 Solution is to make the template template parameter’s template parameters match the template parameters of the C++ standard container classes. template > class CT> class Stack { private: CT elems; public: void push(const T &); void pop(); T top() const; }; … Stack stack; // Okay now. Now, the number of template parameters that std::vector has is the same as the number of template parameters that CT has.

756 Can also be used with function templates. – template > class C> void foo() { C container; } int main() { foo (); }

757 Functions as Type and Non-Type Parameters A function type is also a type. – template class A { void method() { T func; // Okay? func(1); } T *fp; // Okay? T member_func; // Okay? }; A o; A function pointer is a non-type template parameter, however. – template class B; // Okay? template class B { F fp; // Okay? R (*fp2)(P) = F; // Okay? }; int func(double); B obj;

758 More On Non-Type Template Parameters The main requirement is that it be constant. You can do things like this: – template T addValue(const T &x) { return x + VAL; } You cannot use doubles, or string literals: – template double func(double x) { … } // Syntax error. – template class MyClass { … }; MyClass obj; // Error. extern const char s[] = “hello”; MyClass x; // Okay. – Why are string literals not allowed?

759 What does this do? – template class Incrementor { public: Incrementor(T *p) : obj(p) {} void inc() { (obj->*mptr)++; } private: T *obj; }; struct A { int value1; int value2; } a; Incrementor inc1(&a); Incrementor inc2(&a); inc1.inc(); inc2.inc(); inc2.inc();

760 Zero Initialization One of the issues with templates is the distinction between “fundamental” values, like int, double, etc. and “objects”. – The same code should work for both. – In Java, one way around this the Integer class. In C++, this mainly shows up in initialization issues. – template void foo() { T x; // Is this initialized? } – Depends on whether it is a fundamental type or not.

761 Solved by defining int() to be zero. – template void foo() { T x = T(); } template class A { public: A(); private: T x; … }; template A ::A() : x() {…}

762 .template In some situations, there is a similar type of ambiguity to the typename issue. Is this a syntax error? – template void print(const bitgroup &bs) { std::cout (); } Disambiguate with template keyword. – template void print(const bitgroup &bs) { std::cout (); }

763 String Literals in Template Argument Deduction Consider: – template const T &max(const T &a, const T &b) { … } … max(“a”, “b”); // Okay. max(“aa”, “bb”); // Okay. max(“a”, “bb”); // Is this okay? The issue is that the type of a string literal like “a” is const char[2]. If you use a non-reference parameter, on the other hand, the array-to-pointer decay will occur. – template T max(T a, T b) { … } … max(“a”, “b”); // Okay. max(“a”, “bb”); // Okay. You can kind of solve this with an overloaded template, but it doesn’t help much anyway, due to the return type. – template ??? max(const T (&a1)[N1], const T (&a2)[N2]) {... }

764 Argument Dependent Lookup (Koenig) Remember that operators for objects are just a kind of “syntactic sugar” for functions: – if (a < b) {…} is exactly the same as – if (operator<(a,b)) { … } This is a function call!

765 Consider this: – // Library A code. class BigInt {…}; // Assume operator = defined. bool operator inline const T &max(const T &a, const T &b) { return a < b ? a : b; } // User code. void foo(const BigInt &bi1, const BigInt &bi2) { BigInt x = max(b1, b2); // Okay? } Should there be namespaces somewhere here?

766 So being good C++ citizens, we add namespaces: – // Library A code. namespace cs540 { class BigInt {…}; // Assume operator = defined. bool operator inline const T &max(const T &a, const T &b) { return a < b ? a : b; } } // User code. void foo(const cs540::BigInt &bi1, const cs540::BigInt &bi2) { cs540::BigInt x = std::max(b1, b2); // Okay? } Does this still work?

767 The < operator is in a different namespace from the template. But ADL says that names should be looked up in scopes associated with the arguments. – Dependent qualified names are looked up. – ADL is done for unqualified names. Using directives are ignored during ADL, but using declarations are obeyed.

768 Consider this: – namespace cs540 { class A { … }; void foo(const A &a); std::ostream & operator<<(std::ostream &os, const A &); } int main() { cs540::A a; cs540::foo(a); // Okay? foo(a); // Also, okay? operator<<(std::cout, a); // Okay? std::cout << a << endl; // Okay? }

769 Consider this: – namespace cs540 { class A { … }; void foo(const A &a) { … } } int main() { cs540::A a; cs540::foo(a); // Okay? foo(a); // Okay? } // Which one does it call? void foo(const cs540::A &a) { … }

770 Consider this: – namespace ns { class X {... }; template void select(X*); } void g(ns::X *xp) { select (xp); // Does ADL work here? } There are two ways to parse the above: – Function name Arg select (xp) – Comparison Comparison select (xp) The question is whether or not xp is a function call argument. – If yes, then ADL will apply. – If not, then ADL does not apply. – But whether or not it is a function call argument depends on whether or not is a template argument....but this depends on whether or not xp is a function call argument...but this depends on whether or not is a template argument....

771 Argument Dependent Lookup (ADL) Does this code work? – namespace ns1 { class A {... }; bool comp(const A &, const A &); } template void foo(const T &o, const T &o) { if (comp(o1, o2) {... } }... ns1::A a1, a2; foo(a1, a2);

772 Digraphs Suppose you were kidnapped by aliens. They said they would blow up earth unless you could write a C++ program to create a ten element array of integers and assign 1234 to the first element. No problem. They, being evil, give you a computer with a keyboard with a broken square bracket key. What do you do? Use digraphs: – #include int main() { int a ; // a[10] a = 1234; printf("%d\n", a ); }

773 Friend Name Injection Consider this: – template class A { friend void f(); friend void f(const A &); }; void g(A *p) { f(); // Okay? f(*p); // Okay? } Upshot is that friend functions are found if they are friends of classes that are part of the ADL.

774 Class Name Injection Inside a template, the class name can be used alone: – template class C { C foo(); C goo(); }; – In this case, it is considered to be shorthand for C, which is not a template. This means that o.foo() returns an object of type C if o is of type C, etc.

775 template class TT> class X { }; template class C { C *a; C b; X c; X d; };

776 Another Example Consider a range-checked, statically allocated Array class: – Assignment operator – Converting assignment operator – bool specialization

777 Dependent and Nondependent Names Within a template, there are two types of names. – dependent: The exact meaning depends on a template parameter. – nondependent: The exact meaning does not depend on a template parameter. Which are dependent/nondependent? – template Type min(Type *array, int size) { Type min_val = array[0]; for (int i = 1; i < size; i++) { if (array[i] < min_val) { min_val = array[i]; } } print("Min found: "); print(min_val); return min_val; }

778 Consider two translation units containing the below: – First translation unit: template void foo(T v) { func(v); // func() is not declared yet. // print() is not declared yet. print(“hello”); } – Second translation unit: void func(int); void print(const char *); foo(1); Does this compile?

779 Name Resolution Name lookup occurs in two phases. – In the first phase, nondependent names are resolved where they are used. Thus, all names not dependent on a template must be declared at point of template definition. – In the second phase, dependent names are resolved at the point of instantiation. Thus, all names dependent on a template not resolved till point of instantiation.

780 Point of Instantiation (POI) The point of instantiation (POI) of a function template is always in namespace scope, and occurs immediately after the function that instantiated it. – int main() { … min(…); // Use of a function template min(). } // <<<< POI of the use above is here. What if the same function is instantiated multiple times? – Compiler can pick any POI. What if in more than one file? – Compiler can pick any one.

781 Why is the POI after the use of a function template, rather than before? Consider: – template void f(T o) { if (o > 0) { g(o); // ? } } … // Possible POI 1 void g(FooType ft) { f (ft); } // Possible POI 2

782 ADL and PoI class MyInt { public: MyInt(int i); }; MyInt operator-(const MyInt &); bool operator>(const MyInt &, const MyInt &); typedef MyInt Int; void g(Int); template void f(T i) { if (i > 0) { g(-i); } void g(Int) { f (42); }

783 Where should the POI of a class template be? – template class S { public: T m; }; // Possible POI 1 unsigned long h() { return (unsigned long) sizeof(S ); } // Possible POI 2 The point of instantiation (POI) of a class template is always in namespace scope, and immediately precedes the declaration or definition that uses the instantiation. The POI of a member function or static data member immediately follows it's use.

784 Barton-Nackman Trick Friends can also define functions inline: – class A { friend void foo() { … } … }; What is the scope of these? Are these static member functions? – They are at namespace scope, but are “hidden”. They are not static member functions.

785 If you define functions as part of a template, it essentially allows you to define free-standing functions as part of a template instantiation. – template class A { public: // Non-template function. friend void foo(A a) { … } … }; … A a; // Where can foo(A ) be found?

786 A technique that can be useful sometimes: – template class NotEqualMixin { public: friend bool operator!=(const T &v1, const T &v2) { return !(v1 == v2); } }; class A : public NotEqualMixin { public: friend bool operator==(const A &, const A &); }; int main() { A a1, a2; a1 == a2; a1 != a2; }

787 Further examples: – template class A { … }; template class A { … };

788 Specialize whole class template – template class A {…}; template <> class A {…}; Where do these go? Traits – template <> class Traits { static const Color hair_color = BLACK; static const Color eye_color = BLACK; static const int weight = 135; }; template <> class Traits {…}; color = Traits ::hair_color;

789 Using this->

790 RAII (Resource Acquisition Is Initialization) Consider: – void foo() { char *a = new char[50]; … return; … return; … return; } How do we avoid memory leaks?

791 Instantiation Inclusion models Explicit instantiation.

792 – What happens if later on in this translation unit you have: foo(4); foo(3.14); – What happens if later on in a different translation unit you have: foo(5); Explicitly – template void foo (int); – What happens if later on in this translation unit you have: template void foo (int); foo(4); What happens if a template is implicitly instantiated in one translation unit, and explicitly in another? What if it is first implicitly instantiated, then explicitly instantiated in the same translation unit? Trying to remember all the rules will drive you crazy. – Instead understand the purpose of instantiation, and understand the underlying techniques. – This will help you immensely when trying to track down errors.

793 Template Aliases A typedef can only be made to a concrete type. Recall our template template parameter example: – template class MySimpleContainer { … }; template class C> class A { C container; }; int main() { A a1; A a; } – What’s the problem?

794 You can solve this by creating a template alias: – template class MySimpleContainer { … }; template class C> class A { C container; }; template using myvector = std::vector >; int main() { A a1; A a; }

795 std::map takes two template arguments, the key and value. – map Let’s say that you were tired of typing the first template argument. You can use a template alias: – template using mymap = map ; – mymap m;

796 Repetitive Code Suppose you are writing some code, and you see that the following lines repeated 4 times in your code within a single function: – Local variables are in blue, code that is not the same in all four occurrences is in red. – … Element *e = new Element(bindings_table.lookup(String()), String(st_name_bc_begin, p)); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, String(st_name_bc_begin, p), binding_list_head); …

797 – … Element *e = new Element(bindings_table.lookup(elem_prefix), String(st_name_ac_begin, p)); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, String(st_name_bc_begin, p), binding_list_head); … Element *e = new Element(bindings_table.lookup(elem_prefix), name); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, check_name, binding_list_head); …

798 – … Element *e = new Element(bindings_table.lookup(elem_prefix), name); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, check_name, binding_list_head); … Pattern is: – … Element *e = new Element(bindings_table.lookup(str1), str2); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, str3, binding_list_head); … So what? Solution?

799 You could use a function: – void create_element( BindingTable *bt, Element **root, ElementStack *es, const BindingTable::Binding *blh, const String &pref, const String &nm, const String &cn) { Element *e = new Element(bt->lookup(pref), nm); if (*root != 0) { es->top().element->add_child(e); } else { *root = e; } es->push(e, cn, blh); }

800 Which would then be called with: – create_element(&bindings_table, &root, &element_stack, binding_list_head, String(), String(st_name_bc_begin, p), String(st_name_bc_begin, p)); create_element(&bindings_table, &root, &element_stack, binding_list_head, elem_prefix, String(st_name_ac_begin, p), String(st_name_bc_begin, p)); create_element(&bindings_table, &root, &element_stack, binding_list_head, elem_prefix, name, check_name); create_element(&bindings_table, &root, &element_stack, binding_list_head, elem_prefix, name, check_name); Other options?

801 You could use a local class to encapsulate a function. – struct Locals { void create_element(const String &pref, const String &nm, const String &cn) { Element *e = new Element( bindings_table->lookup(pref), nm); if (root != 0) { element_stack.top().element->add_child(e); } else { root = e; } element_stack.push(e, cn, binding_list_head); } BindingTable bindings_table; ElementStack element_stack; const BindingTable::Binding *binding_list_head; Element *root; } l;

802 It would be used like this: – l.create_element(String(), String(st_name_bc_begin, p), String(st_name_bc_begin, p)); l.create_element(elem_prefix, String(st_name_ac_begin, p), String(st_name_bc_begin, p)); l.create_element(elem_prefix, name, check_name); l.create_element(elem_prefix, name, check_name); … l.bindings_table.accessor() …;

803 Note that you are using the local class to create a local function that “captures” some local variables. You can do that explicitly using lambda in C++11.

804 Lambda Lambda allows you to create anonymous functions. Example: – cout << [](int x){return x + 3;}(4) << endl; – auto doit = [] (int x) { return x + 2; } cout << doit(1) << endl; In the body, you can only use captured variables: – int i, j; auto doit = [i] () { cout << i << endl; // Okay. cout << j << endl; // Syntax error. } You can capture by reference, also: – int i = 1, j = 2; auto doit = [&i, j]() { i = 3; // Okay. }

805 You can capture implicitly (default): – int i = 1, j = 2; auto doit = [&, i]() { j = 1; // Implicit capture by reference. i = 3; // Error, captured by value. } – int i = 1, j = 2; auto doit = [=, &j]() { i = 2; // Error, implicit capture by value. j = 3; // Okay. } You change variables captured by value by creating mutable lambdas, but it won’t change the outer: – int i = 1, j = 2; auto doit = [&, i]() mutable { j = 1; // Implicit capture by reference. i = 3; // Okay, doesn’t change outer. }

806 The return type can be inferred if just one return statement or void. – auto l1 = [] () { return 1234; }; – auto l2 = [](int n) { for (int i = 0; i < n; i++) { cout << i << endl; } }; Otherwise, must use a trailing return type. – auto l3 = [](int n) mutable -> int { if (n%2 == 0) { return 1; } else { return ‘a’; } }; In C++14, return type deduction works even if not just a single return statement, and also works for non-lambda.

807 A common task is to apply a small bit of code to all the elements in some container. – #include #include #include using namespace std; void f(int i) { cout a{{1, 2, 3, 4, 5}}; for_each(a.begin(), a.end(), f); }

808 What if we want to collect all odd elements? – #include #include #include #include using namespace std; class CollectOdd { public: Odd(vector *v) : vec(v) {} void operator()(int i) { if (i%2 == 1) { vec->push_back(i); } } private: vector *vec; }; – int main() { array a{{1, 2, 3, 4, 5}}; vector result; CollectOdd f(&result); for_each(a.begin(), a.end(), f); for (auto i : result) { cout << i << endl; } }

809 Can be done with lambda. – #include #include #include using namespace std; int main() { array a{{1, 2, 3, 4, 5}}; vector result; for_each(a.begin(), a.end(), [&](int i) { if (i%2 == 1) { result.push_back(i); } } ); }

810 Lambdas can be put into variables: – auto f = [](int i) { return 2*i; }; auto j = f(2); To pass a lambda into a non-template function, use std::function : – void f(const std::function &f) { int i = f(2); … } f([](int i) { return 2*i; });

811 In C++14, you can have generic lambdas (more or less like a templated lambda). Handy in two ways: – // C++11 auto sqr1 = [](int x) {return x*x; }; double x = sqr1(3.14); // C++14 auto sqr2 = [](auto x) { return x*x; }; int i = sqr(9); // Does the right thing. double x2 = sqr(3.14); // Does the right thing. – // Also allows compiler to figure out // types for you. std::sort(cont.begin(), cont.end(), [](auto i, auto j) { return (i > j); });

812 [C++14] Generic lambdas can also be variadic: – auto output auto l = [](auto… params) {

813 Also, in C++14, you can have generalized capture: – int i; auto l = [&v1 = i, v2 = 2*i, v3 = 1]() mutable { v1 = 3; // Sets i. cout << v3++ << endl; }; l(); l();

814 Variadic Templates In C++11, templates can have varying number of template and function arguments. – template void f(Ts... params) { … } Example, a variadic function template to sum its args: – template const T &sum(const T &v) { return v; } template T sum(const T &v, const Ts &... params) { return v + sum(params...); } … sum(1); sum(1, 2); sum(1.1, 2.2, 3.3); BigInt bi1, bi2, bi3; sum(bi1, bi2, bi3, 3);

815 You can get the number of parameters in the pack with sizeof... : – template void foo(const Ts & … params) { cout << sizeof…(Ts) << endl; cout << sizeof…(params) << endl; }

816 Class templates can also be variadic: – template class A { … }; Non-type parameters can also be variadic: – template class A { … };

817 Expansion can be a pattern: – template void out(const T &v) { cout void pass(const Ts &... params) {} template void foo(const Ts &... params) { pass(out(params)...); } – foo(1, 1.3); expands to pass(out(1), out(1.3));

818 Expansion can be a pattern: – template void out(const T &v) { cout void pass(const Ts &... params) {} template void foo(const Ts &... params) { pass(out(params)...); } – foo(1, 1.3); expands to pass(out(1), out(1.3)); – Okay? pass((out(params), 1)...);

819 Variadic templates can interact with name lookup in unfortunate ways. Reconsider our variadic sum function. – template const T &sum(const T &v) { return v; } template T sum(const T &v, const Ts &... params) { return v + sum(params...); } – sum(1, 3.1); // Returns?

820 A possible solution is to attempt to use a trailing decltype. – template const T &sum(const T &v) { return v; } template auto sum(const T &v, const Ts &... params) -> decltype(v + sum(params...)) { return v + sum(params...); } … sum(1, 2.1, 3); // POI should be after this. Does this compile? – No, because the point of declaration for a function is after the trailing return type, so the sum in the trailing return type doesn’t match the function template. – But if names are looked up at the POI, which is after the use, then the function template has been declared already. – But only an ADL is done at the POI, and the ADL for a built-in type does nothing. Solution?

821 We can use an auxiliary helper class just to compute the return type. – template struct Helper { using sum_t = decltype(T() + typename Helper ::sum_t()); } template struct Helper { using sum_t = T; }; template const T &sum(const T &v) { return v; } template auto sum(const T1 &v1, const Ts &... params) -> typename Helper ::sum_t { return v1 + sum(params... ); } – Does this compute the type (v1 + (v2 + v3)), or the type of ((v1 + v2) + v3)? Is there a difference? No difference for built-in types, but there could be a difference for user-defined types. A + B  C, C + C ->D, B + C -> E, A + E -> F A + B + C Other solutions?

822 Remember that ADL will kick in at the POI if we can cause a dependency on a non- built-in type. So maybe we can artificially introduce one. – template const T &sum_helper(const D &d, const T &v) { return v; } template auto sum_helper(const D &d, const T1 &v1, const Ts &... params) -> decltype(v1 + sum_helper(d, params...)) { return v1 + sum_helper(d, params... ); } class A {}; template auto sum(const Ts &... params) -> decltype(sum_helper(A(), params...)) { return sum_helper(A(), params...); }

823 /* A pack argument must correspond exactly to a pack parameter in an alias template. */ template struct Set {}; template using Tail = Set ; template using Alias1 = Tail ; // ERROR, but clang++ 3.4 doesn't catch it. g++ 4.9.0 does. template using Alias2 = Tail ; // Okay.

824 /* Let's say you have a function template like this. */ template void foo(T, U) { } /* You can specialize it for any specific T and U. */ template <> void foo (int, double) {} /* You can not specialize it for when T is an int, and U is free, because that is a partial specialization. */ // Below is a syntax error. template void foo (int, U) {} /* However, you can simply overload it and achieve the same effect. */ template void foo(int, U) {} /* Now consider a function template like this. */ template void foo2() {} /* You can specialize it for any specific N and M. */ template <> void foo2 () {} /* But you can not specialize it for when N is 1 and M is free, because that is a partial specialization. */ template void foo2 () {} /* In this case, you cannot easily overload it. */ // Hope to resolve to this when 1 is passed as the first argument? // Can't work. template void foo2(int i when it is 1) {} /* What you can do, however, is to use a class just to capture the two integer template parameters. You can then overload on that. That works. */ template struct sequence {}; template void foo2(const sequence &) {} template void foo2(const sequence &) {}

825 Friends defined in a class. #include using namespace std; // Forward decl. template class A; template void foo(const A &a) { int i = a.i; cout << "Template foo()" << endl; } template class A { friend void foo(const A &) { cout << "Non-template, in-class friend foo()" << endl; } friend void foo<>(const A &); /* // The below causes a re-definition error on g++, but not clang++. template friend void goo(const A &) { cout << "goo1()" << endl; } */ // This is fine on both g++ and clang++. template friend void goo(const A &, const A &) { cout << "goo2()" << endl; } private: int i; }; int main() { A a1; A a2; A a3; foo(a1); foo<>(a1); //goo(a2); goo(a2, a1); goo(a1, a2); goo(a1, a1); goo(a2, a2); }

826 New friend specifier: – https://www.ibm.com/developerworks/communit y/blogs/5894415f-be62-4bc0-81c5- 3956e82276f3/entry/introduction_to_the_c_11_f eature_extended_friend_declaration3?lang=en https://www.ibm.com/developerworks/communit y/blogs/5894415f-be62-4bc0-81c5- 3956e82276f3/entry/introduction_to_the_c_11_f eature_extended_friend_declaration3?lang=en


Download ppt "Accelerated C/C++ Advanced OOP CS 440/540 Spring 2015 Kenneth Chiu."

Similar presentations


Ads by Google