Download presentation
Presentation is loading. Please wait.
Published byDeborah Nora McLaughlin Modified over 7 years ago
1
CS 3370 – C++ Chapter 1 (portions from Lippman, C++ Primer)
Introduction CS 3370 – C++ Chapter 1 (portions from Lippman, C++ Primer)
2
A Little History Early 1980s 1985 1989 1998 2011 added objects to C
1.0 goes public 1989 2.0 (modern I/O streams, multiple inheritance) Standards Committee organized 1998 1st ISO Standard 2011 2nd ISO Standard
3
Key Features Compiles to native, executable code (FAST!)
There are no classes at runtime – just bits and bytes. Supports multiple programming paradigms Imperative (procedural) Object-oriented Generic Functional (somewhat) Used Everywhere Web servers Compilers Operating systems Games Algorithmic trading
4
Legacy Features Built on C C Pointer Operators Headers Files
An old language (1970) An ubiquitous language! C Pointer Operators & – address-of * – indirection -> – pointer-to-member (p->mem == (*p).mem) Headers Files Separate .h and .cpp files Statically sized arrays Fixed at compile time Declaration vs. Definition
5
New C++11 Features Range-based for loop Lambda expressions
Uniform Initialization Syntax Generic Function Argument Binding rvalue References and Move Semantics Type inference with auto and decltype Sophisticated Smart Pointers Object control with =default and =delete Variable-length Template Arguments final classes and methods; override methods New containers (hash tables, smart arrays…) Support for concurrent programming, regular expressions…
6
Compilers to Use Windows Mac/Linux Visual C++ 2013
Available from Dreamspark Or download Visual Studio Express 2013 for Windows Desktop Mac/Linux Latest version of clang Comes with Xcode on Mac
7
A First Program // sumnums.cpp: Sums numbers read from standard input (cin) #include <iostream> using namespace std; // Opens up entire namespace int main() { // Never use void with main int sum = 0, value = 0; while (cin >> value) // Note EOF check! sum += value; cout << "sum: " << sum << endl; } Discuss: using, namespaces (see Lippman book version on next slide), int main Do live from keyboard.
8
With Qualified Names // sumnums2.cpp: Sums numbers read from standard input // Doesn’t use “using” #include <iostream> int main() { int sum = 0, value = 0; while (std::cin >> value) sum += value; std::cout << "sum: " << sum << std::endl; }
9
With using Declarations
// sumnums3.cpp: Sums numbers read from standard input #include <iostream> // Only the following 3 names are imported using std::cin; using std::cout; using std::endl; int main() { int sum = 0, value = 0; while (cin >> value) sum += value; cout << "sum: " << sum << endl; }
10
Types and Variables A type defines a set of values and associated operations A value is a set of bits interpreted as some type An object is some memory that holds a value of some type has an address (an "lvalue") We will use “instance” for objects of classes A variable is a named object (see p. 5 in TOC++) Not all objects have names (e.g., heap objects).
11
The auto Type Specifier
New in C++11 Infers the type of a variable from its initializer like var in C# Handy for hard-to-remember types vector<int>::iterator p = v.begin(); // C++98 auto p = v.begin(); // or begin(v); C++11
12
Uniform Initialization Syntax
Handy, but not required Can be used for all initializations Built-ins, class constructors Uses curly braces int n{2}; int a[]{1,2,3}; vector<int> v{1,2,3}; map<string,int> m{{“one”,1},{“two”,2}}; See also: newinit.cpp
13
Declarations vs. Definitions
Declarations introduce a name into a scope Definitions provide complete implementation detail Most declarations are also definitions: int x; // Space is reserved for object, which will be used as an int These can be separated in C++ And sometimes must be Declarations that are not definitions: void f(int); // A Function declaration class C; // A Class declaration Declaration aka “prototype”. Class declarations allow use of pointers and references to instances.
14
Scope The region of visibility for names in a program Local scope:
Visible from its point of declaration to the end of its block { … } Function declarations have no block, so scope ends at semi-colon Class scope: Names declared directly within a class definition (aka members) Visible in the class definition and member function implementations Namespace scope: Names declared within an explicitly defined namespace Visible from point of declaration to end of namespace { … } block Global scope: A name declared outside of any of the above
15
Built-inTypes (From Lippman et al)
Types aren’t uniform across platforms! (From Lippman et al)
16
Sizes of Numeric Types Not uniform across platforms
int, long, etc. differ from platform to platform Signed vs. unsigned integers integer types may be declared unsigned sometimes tricky (silent overflow => modular arithmetic) Don’t mix the two! The .size( ) function always returns unsigned integers (size_t) size_t is defined in <cstddef> for (size_t i = 0; i < v.size(); ++i) … for (int i = 0; i < static_cast<int>(v.size()); ++i) for (int i = 0; i < int(v.size()); ++i) … There is a risk of overflow going from unsigned to signed.
17
Numeric Type Conversions
Widening conversions smaller to larger types allowed implicitly but can lose precision converting from integer to floating-point types! Narrowing conversions larger to smaller types NOT implicitly allowed (new feature in C++2011)! require a cast: int n = static_cast<int>(x);
18
C++ Casts static_cast dynamic_cast reinterpret_cast
converts among “related types” (e.g., numbers) restore a pointer from a void* dynamic_cast for “downcast” tests in class hierarchies reinterpret_cast for low-level tomfoolery e.g., casting from int to pointer casting among unrelated pointer types (see Program 1!) const_cast (to remove const; rarely used)
19
Compound Types Types you build from other types Examples:
ultimately, all types boil down to built-in components Examples: arrays classes references pointers const adornments
20
What is a Pointer? An address
actually, a variable that holds an address Actual numeric addresses are rarely important except in embedded programming The null pointer special value that points “nowhere” int* p = nullptr; // New in C++11 Similar to “null” in other languages
21
// address.cpp: Illustrates the address-of op (&)
#include <iostream> using namespace std; int main() { int i = 7, j = 8; cout << "i == " << i << ", &i == " << &i << endl; cout << "j == " << j << ", &j == " << &j << endl; } /* Output: i == 7, &i == 0012FF88 j == 8, &j == 0012FF84 */ Draw picture.
22
Pointer Declarations Use an asterisk (*) Must indicate type pointed to
int* p; “p is a pointer to an int” “*p is an int” Must indicate type pointed to pseudo-exception: void * the only thing you can do with a void* is hold an address you can’t dereference it don’t delete it
23
Pointers to Pointers Multiple levels of indirection
Occasionally use multiple indirection levels Given int ** p; … **p is an int => *p is a pointer to an int => p is a pointer to a pointer to an int
24
#include <iostream> using namespace std; int main() { int i = 7;
int main() { int i = 7; int* ip = &i; int** ipp = &ip; cout << "Address " << ip << " contains " << *ip << endl; cout << "Address " << ipp << " contains " << *ipp cout << "**ipp == " << **ipp << endl; } // Output: Address 0x7fff5e8f3cbc contains 7 Address 0x7fff5e8f3cb0 contains 0x7fff5e8f3cbc **ipp == 7 Draw picture
25
The const Qualifier Indicates that the item being defined is read-only
const variables must be initialized when defined
26
Pointers and const const before the asterisk ⇒ const contents
“p is a pointer to a const int” const after the asterisk ⇒ const pointer “p is a const pointer to an int” const char * p1; // *p1 = ‘c’ illegal; ++p1 OK char const * p1; // (same as above) char * const p2; // *p2 = ‘c’ OK; ++p2 illegal const char * const p3 = "fixed";// neither allowed
27
Assigning non-const to const
Always okay (no loss of safety) Example: char* p; … const char* q = p; p doesn’t care if you modify its contents; but q won’t anyway Many char* arguments in the C library are const Going the other way (const to non-const) loses safety; should be rare and requires a cast
28
Assigning const to non-const
Not allowed (loses const protection) Should be rare and requires a cast: const char * p = …; char* q = const_cast<char*>(p); // lose the const *q = …; Note the missing const in brackets.
29
Multiple Indirection and const
A “dark corner” Cannot convert char** to const char** Must add const at all levels to the left of the right-most star: we’re protecting the contents, not the pointer anything to the left of the right-most asterisk refers to the contents const char * const * Example: multconst.cpp, multconst3.cpp
30
Generic Pointers void *
Allows holding a pointer to any type Must explicitly cast back to original type to use Used often for function parameters Useful for: reinterpreting any object as a sequence of bytes implementing low-level, generic containers
31
Implementing memcpy( )
void* memcpy(void* target, const void* source, size_t n) { // Copy any object to another char* targetp = static_cast<char*>(target); const char* sourcep = static_cast<const char*>(source); while (n--) *targetp++ = *sourcep++; return target; } int main() float x = 1.0, y = 2.0; memcpy(&x, &y, sizeof x); // same as x = y cout << x << endl; // 2 From <cstring>
32
Another void* example inspect( ) function Receives a void* parameter
Prints the bytes of any object Receives a void* parameter Actually const void* Converts to a const char* to inspect bytes actually const unsigned char* for hexadecimal printing Mention sign extension.
33
int main() { char c = 'a'; short i = 100; long n = L; double pi = ; char s[] = "hello"; inspect(&c, sizeof c); cout << endl; inspect(&i, sizeof i); cout << endl; inspect(&n, sizeof n); cout << endl; inspect(&pi, sizeof pi); cout << endl; inspect(s, sizeof s); cout << endl; } // Output: byte 0: 61 byte 0: 64 byte 1: 00 byte 0: a0 byte 1: 86 byte 2: 01 byte 3: 00 byte 0: 13 byte 1: 7c byte 2: d3 byte 3: f4 byte 4: d9 byte 5: 21 byte 6: 09 byte 7: 40 byte 0: 68 byte 1: 65 byte 2: 6c byte 3: 6c byte 4: 6f byte 5: 00
34
// inspect.cpp: Inspect the bytes of an object
#include <iostream> #include <iomanip> // For setfill using namespace std; void inspect(const void* ptr, size_t nbytes) { const unsigned char* p = static_cast<const unsigned char*>(ptr); cout << hex; for (size_t i = 0; i < nbytes; ++i) cout << "byte " << setw(2) << setfill(' ') << i << ": " << setw(2) << setfill('0') << size_t(p[i]) << endl; cout.fill(' '); // Restore blank fill cout << dec; } static_cast used to cast from a void*. Note setfill. Note the int cast for printing char as int.
35
Yet Another void* Example
Illustrates C’s qsort function which you may never need to use! Illustrates casting a void* to an int See sortints.cpp See also sortStrings.cpp, sortStrings2.cpp Carefully go through these.
36
Built-in Arrays Size determined statically (i.e., at compile time)
Dimension must be a compile-time constant Not a non-const variable Can use range-based for loop with arrays but only in the scope in which the array is defined int a[]{1,2,3}; for (auto x: a) // range-based for loop cout << x << ' '; // 1 2 3 cout << endl; int b[5]{1,2,3}; // initializes rest for (auto x: b) cout << x << ' '; //
37
Pointers and Arrays Remember this!
Array names in expressions “decay” into a pointer to the 1st element Except when an operand to sizeof e.g, when passed as a parameter to a function or with pointer arithmetic (a + i == &a[i]) a is the same as &a[0] ⇒ *a == a[0] ⇒ a + i == &a[i] ⇒ *(a + i) == a[i] *(p + i) == p[i] // *** for any pointer *** Remember this!
38
Implementing strcpy( )
// Arrays are passed to strcpy char* strcpy(char* dest, const char* source) { char* save = dest; while (*dest++ = *source++) // Note '=’. ; // Empty body! return save; }
39
Array Size Idiom Given int a[n]; // where n is const
n == sizeof a / sizeof a[0] Computes at compile time! Only valid when the array definition is in scope Can’t work for arrays as function parameters Because they are passed as pointers only Not the most useful idiom, admittedly
40
Multi-dimensional Arrays
Don’t really exist! “Array of arrays” model int a[2][3] an array of 2 elements each element is an array of 3 ints what is sizeof(a[0])? sizeof(a[0]) = 3 * sizeof(int). Draw a picture.
41
int a[][3] = {{1,2,3},{4,5,6},{7,8,9}}; cout << "sizeof(a): " << sizeof(a) << endl; size_t n = sizeof(a) / sizeof(a[0]); for (size_t i = 0; i < n; ++i) { cout << "sizeof(a[" << i << "]): " << sizeof(a[i]) << endl; size_t m = sizeof(a[i]) / sizeof(int); for (size_t j = 0; j < m; ++j) cout << "sizeof(" << a[i][j] << "): " << sizeof(a[i][j]) << endl;
42
/* Output: sizeof(a): 36 sizeof(a[0]): 12 sizeof(1): 4 sizeof(2): 4 sizeof(3): 4 sizeof(a[1]): 12 sizeof(4): 4 sizeof(5): 4 sizeof(6): 4 sizeof(a[2]): 12 sizeof(7): 4 sizeof(8): 4 sizeof(9): 4 */
43
Question How do you declare a pointer, p, for the following: ??? = new int[2][3]; Remember: arrays are really one-dimensional Remember also: new returns a pointer to the first element of the requested array What is the type of each top-level element? Key: what kind of thing is the first element of the requested array? It is an array of 3 ints; So p is a pointer to an array of 3 ints. What is sizeof(*p).
44
Discovering The Type With auto
int main() { auto p = new int [2][3]; cout << sizeof(p) << endl; // 8 cout << typeid(p).name() << endl; // PA3_i cout << sizeof(*p) << endl; // 12 cout << typeid(*p).name() << endl; // A3_i } Pointers are 8 bytes on my 64-bit platform.
45
cout << "sizeof(p): " << sizeof(p) << endl;
int a[][3] = {{1,2,3},{4,5,6},{7,8,9}}; int (*p)[3] = a; cout << "sizeof(p): " << sizeof(p) << endl; cout << "sizeof(*p): " << sizeof(*p) << endl; size_t n = sizeof(a) / sizeof(a[0]); for (size_t i = 0; i < n; ++i) { cout << "sizeof(p[" << i << "]): " << sizeof(p[i]) << endl; size_t m = sizeof(a[i]) / sizeof(int); for (size_t j = 0; j < m; ++j) cout << "sizeof(" << p[i][j] << "): “ << sizeof(p[i][j]) << endl; Note the decay in the second line.
46
/* Output: sizeof(p): 8 sizeof(*p): 12 sizeof(1): 4 sizeof(2): 4
*/ 64-bit platform has pointer size 8.
47
Higher and Deeper Repeat the process on the 3-d array: int a[2][3][4];
See sizeof3.cpp Draw picture. int (*p)[3][4] = new int[2][3][4];
48
Arrays and Range-based for Loops
Iterates through top-level elements just like it always does Multidimensional arrays require using reference loop variables except on innermost (last) dimension built-in arrays aren’t copied like values See next slide…
49
for (const auto &row: a) { // Note &
int a[][3] = {{1,2,3},{4,5,6},{7,8,9}}; for (const auto &row: a) { // Note & cout << "sizeof(row): " << sizeof(row) << endl; for (const auto x: row) cout << "sizeof(" << x << "): " << sizeof(x) << endl; } /* Output: sizeof(row): 12 sizeof(1): 4 sizeof(2): 4 sizeof(3): 4 sizeof(4): 4 sizeof(5): 4 sizeof(6): 4 sizeof(7): 4 sizeof(8): 4 sizeof(9): 4 */ This is sizeof2b.cpp.
50
Returning Heap Arrays Not often done
As usual, must return a pointer to the first element and client must manage its deletion So… what is the signature of the function? “f is a function that returns a pointer to an array of 3 ints” auto won’t help you here :-) Note: functions are passed and returned as pointers
51
int (*f())[2] { return new int[7][2]; } int main() { int (*p)[2] = f(); cout << sizeof(p[0]) << endl; // 8 (2 ints) cout << sizeof(p[0][0]) << endl; // 4 delete [] p;
52
How does istream::get work?
char c; cin.get(c); // reads next input byte into c cout << c; // prints the byte read as a char
53
References Can be function parameters Can also be local
Implements “call by reference” Can also be local Merely another name (an alias) for an existing variable Can be return values Used by operator[ ]
54
References are Aliases
#include <iostream> int main() { using namespace std; int i = 7; int& r = i; ++r; cout << i << endl; // 8 }
55
Reference Parameters Implicit Pointer Indirection
#include <iostream> using namespace std; void swap(int& x, int& y) { int temp = x; x = y; y = temp; } int main() int i = 1, j = 2; swap(i,j); cout << "i == " << i << ", j == " << j; /* Output: i == 2, j == 1 */
56
Reference Parameters Transparent access to argument
void f(int x) {cout << &x << endl;} void g(int& x) {cout << &x << endl;} int main() { int n; cout << &n << endl; f(n); g(n); } /* Output: 0x7fff5fbff9ac 0x7fff5fbff98c */
57
Reference Returns Must refer to an object that persists after the return
#include <iostream> int a[4] = {0,1,2,3}; int index = 0; int& current() // Returns a reference { return a[index]; } int main() using namespace std; current() = 10; // replace a[0] index = 3; current() = 20; // replace a[3] for (int i = 0; i < 4; ++i) cout << a[i]; cout << endl; /* Output: */
58
Passing Arrays by Reference
Doable, but not too useful at least no copy is made The size of an array is part of its type! void f(int (&a)[5]) {…} See arrayref.cpp
59
Looking Deeper A reference is like a pointer that applies & and * automatically when needed It can be used on either side of an assignment On the left, it is an lvalue Writes to memory (uses operator=) On the right it is an rvalue Reads from memory (uses converts to Data) See returnref.cpp
60
References and const
61
const Reference Parameters
When you won’t be changing the value The “best of both worlds” Efficiency of call-by-reference Safety of call-by-value (Almost) Always pass objects by (const) reference
62
Home-Grown Dynamic Arrays
Rarely used unless you are a C++ library developer or if you have to do Program 1 :-) Example: holdints.cpp Reads an arbitrarily large number of ints from a file into an expandable array Shows how to manually grow a dynamic array Uses a reference argument to “return” the dynamic array from a function The return value is used to indicate the number of ints read See also holdInts2.cpp, which uses vector instead.
63
Managing the Heap The new and delete operators
C++ does not have garbage collection but it does have deterministic destructors! Can deallocate any resource automatically not just memory! e.g., can unlock a mutex or close a network or database connection runs when a local object goes out of scope or when you use delete on a heap object no need for finally in C++
64
The new and delete Operators
Two versions: Scalar (single object): T* p = new T; // Calls constructor delete p; // Calls destructor Array: T* p = new T[n]; // p points to first element delete [ ] p; delete style must match the allocation ([ ]) Failing to delete is a memory leak Array new calls ctor for each array slot.
65
The new operator Does the following before returning a pointer:
Allocates needed memory on the heap calls the library function operator new( ) Initializes the object by calling the proper constructor
66
The new [ ] operator For Arrays
Does the following before returning a pointer to the first element: Allocates needed memory on the heap calls the library function operator new[ ]( ) Initializes each object by calling the proper constructor The default operator new[] calls operator new
67
The delete operator Does 2 important things:
Calls the destructor for the object Returns the memory to the free store via the library function void operator delete(void*)
68
The delete [ ] operator For Arrays
Calls the destructor for each object in the array Returns the memory to the free store via void operator delete(void*); You must use delete [ ] for arrays The default operator delete[] calls operator delete
69
Overloading the Operators
You can overload all 4 memory functions: operator new(size_t) operator new[ ](size_t) operator delete(void* ) operator delete[ ]( void*) Can be useful for tracing memory operations The array versions are seldom used See memory.cpp
70
Class-based heaps You can manage heap on a class basis
Just provide operator new( ) and operator delete( ) As member functions Must be static Because they’re stand-alone functions, of course Even if you don’t declare them so, they will still be static Example: memory2.cpp, Managed.cpp
71
Preventing Heap Allocation
If you want to disallow allocating object on the heap, declare non-public class allocation functions: protected: void* operator new(size_t){ return nullptr; } void operator delete(void*) {} (It is an interesting mystery that on some platforms, bodies are required for these functions when you declare them) Ideally you should be able to just declare these and dispense with function bodies.
72
Placement new A special-purpose version of the new operator used by library developers Does in-place initialization No memory is allocated! Used in low-level programming e.g., to poke a value at a given memory address see poke.cpp see also Program 1
73
Review Specs for Program 1
74
Operators Unary Binary Ternary -, *, ++, --
higher precedence than binary operators most associate right-to-left Binary most associate left-to-right exception: assignment Ternary Conditional operator: a ? b : c yields a value
75
Precedence and Associativity
Associativity applies to operators of the same precedence left vs. right associativity Full list on page 166
76
lvalues and rvalues Term suggests components of an assignment statement “left = right” lvalue = address (stored data and functions have addresses) rvalue = simple values (e.g., temporaries like x + y) x = y; y’s rvalue is copied to the location indicated by x’s lvalue All this is determined by context rvalue lvalue
77
Unmodifiable lvalues const int n = 7;
n has an address, therefore it has an lvalue but it cannot be modified lvalues are required… with &x, *x, and x[i] // x must be an lvalue modifiable lvalues are required… on the left side of an assignment as the target of -- and ++
78
Order of Evaluation Applies to the operands of binary operators
it is usually unspecified in C++ int i = f1() * f2(); We don’t know which function will execute first don’t depend on the order you write them in use separate, sequential statements if order matters Has nothing to do with pre-vs-post increment.
79
More About ++ (and --) Unary operators
Post is higher precedence than pre! Pre returns an lvalue ++ ++x is legal Post return an rvalue x++ ++ is not legal ++x++ is not legal Consider x = *p++; ++ executes first (!!!) but it yields the un-incremented value then * executes after the assignment, p is incremented as a side effect
80
Sequence Points Points in code where pending side effects are carried out The + operator is not a sequence point: that’s why f1() + f2() was indeterminate Occur with the following operators/contexts: Logical connectives (&&, ||) if (x++ && x > y) … Comma operator if (f1(), f()) … The ? in the ternary operator (f( ) ? x : y) Statements Complete conditions in if, while, for, and switch End of an initializer: int a = x++, b = ++x; // done in order
81
Static vs. Automatic Data
Function parameters and local variables have function scope: they are visible only inside the function body But lifetime is a separate matter dependent on storage class Storage Class: automatic Live and die with the function static Alive for the entire program dynamic Live on heap; programmer controlled
82
A Counter Function int counter() { static int count = 0;
return ++count; } int main() { for (int i = 0; i < 5; ++i) cout << counter() << ' '; // cout << endl;
83
Inline Functions Small, simple functions can be “inlined”
the compiler inserts raw code avoiding function call-and-return overhead use inline keyword before function definition Useful when calling functions from intensive loops Is only a hint to the compiler
84
The constexpr Qualifier
Means more than “read-only” new in C++11 Also means “set at compile time” this allows compile-time optimizations the compiler saves space by substituting the value throughout code can evaluate complex integral expressions at compile time Can only be used with “literal types” simple, built-in types in static storage (not on stack or heap) and pointers or references to them
85
Using constexpr Must be in static storage.
86
constexpr const = “I won’t change this”
constexpr = “I will evaluate this at compile time” if I can See poke2.cpp
87
constexpr Functions Enforces that any contained computations and the return value are compile-time constant i.e., constexpr is transitive
88
<<CAUTION>>
Put inline and constexpr definitions in header files The compiler must have access to the code at all times so it can generate appropriate low-level code. There is no danger of multiple definitions due to multiple includes inline and constexpr item have no “external linkage” the linker can’t see them they are values inserted “inline” in generated code
89
Trailing Return Type (->)
int f(int x) { return x*x; } template<typename T1, typename T2> auto min(T1 t1, T2 t2)->decltype(t1+t2) { // Promote to wider type return t1 < t2 ? t1 : t2; int main() { cout << f(3) << endl; // 9 auto x = min(1.1, 2); cout << x << ", " << typeid(x).name() << endl; // 1.1, d The expression t1 + t2 is not evaluated.
90
Pointers to Functions Most useful when passing functions as arguments
Functions cannot be passed by value (duh) When you pass a function as an argument, a “pointer” is passed You don’t always have to use pointer syntax but you can (makes you a C hacker :-) See funptr.cpp
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.