Presentation is loading. Please wait.

Presentation is loading. Please wait.

CS 3370 – C++ String, Vectors, and Arrays

Similar presentations


Presentation on theme: "CS 3370 – C++ String, Vectors, and Arrays"— Presentation transcript:

1 CS 3370 – C++ String, Vectors, and Arrays
chapter 3 CS 3370 – C++ String, Vectors, and Arrays

2 Defining Namespaces Similar to C# namespaces and packages in Java
namespace MySpace { … … } Can span multiple header files! Namespaces can be nested Namespace data is static (like globals)

3 Namespace using Specifications
3 Types of access syntax: 1) Full qualification: std::cout << s << std::endl; std::vector<int> v; 2) Using Declarations 3) Using Directives Listed in most-to-least restrictive order

4 Using Declarations Import one name at a time:
using std::cout; using std::endl; cout << s << endl; Each using imports a name binding into the local scope as is it had been declared there originally but it refers to the name defined elsewhere (like Python) Applies only to the scope where the using declaration occurs! you can put it inside main or any other scope (good idea) don’t use in header files! because anyone including your header gets that name (may conflict with their names)

5 Using Directives Implicitly imports ALL names from the namespace
using namespace std; i.e., the entire namespace is open for name lookup they’re not really imported Again, applies only to the scope where the using occurs <<DANGER>> Never put in a header file! (You already know why!)

6 Namespace Aliases A shorthand for using long namespace names
#include “somebodysheaderfile.h” namespace ns = somebodyslongnamespacename; ns::foo(1); Suppose somebodyslongnamespacename defines foo

7 The Anonymous Namespace
A special namespace unique to each .cpp file Allows defining names with file scope accessible throughout the .cpp file but not accessible from any other .cpp file <<C Hacker Note: this is an alternative to file-level static>> can in discontiguous sections within the file see next slide

8 Anonymous Namespace Example
namespace { int x = 1; int f(int); } /* normal code here … can use f() … */ namespace { int f(int n) {return n+x;} } All in the same file.

9 Using C Headers In C you say, for example: #include <ctype.h>
In C++ you should say: #include <cctype> Extra ‘c’ in front, no “.h” Do this for all C headers This puts them in the std namespace for uniformity

10 Strings

11 Strings are Objects The type is std::string
Defined in the <string> header Has the usual set of string operations Underneath, the implementation manages a dynamic, zero-terminated array of characters C-style

12 String Operators Emphasize getline.

13 Reading Strings The >> operator splits on whitespace
Do this live.

14 Reading Lines Use the overload of getline defined in <string>

15 Range-based for Loop New in C++11

16 <cctype> Functions

17 Using <cctype> Counts the number of punct chars. I think s.size() still returns a size_t? All containers have a size() function.

18 Range-based for and References
Two purposes: 1) doesn’t copy the current value to the loop variable 2) allows changing the sequence element directly (unless const ref)

19 Subscript Iteration Note the use of decltype. This finesses signed/unsigned problems. I still use size_t out of habit.

20 String Iterators int main() { string s("Now is the time!");
for (auto iter = s.begin(); iter != s.end(); ++iter) *iter = toupper(*iter); cout << s << endl; }

21 Alternate begin/end Syntax
Accommodates built-in arrays Works for all containers with iterators begin(c) maps to c.begin() as needed int main() { string s("hello"); for (auto p = begin(s); p != end(s); ++p) cout << *p; // hello cout << endl; int a[] = {1,2,3,4,5}; for (auto p = begin(a); p != end(a); ++p) cout << *p << ' '; // }

22 vectors

23 std::vector A dynamic, array-like container
typically implemented with a heap array Grows to the right (higher indexes) Supports random access Provides iterators Key methods: push_back(x) pop_back front back size empty

24 Uniform Initialization Syntax
New in C++11 Comma-separated sequence in curly braces “Initializer lists” Can initialize any container vector<int> v{1,2,3}; string s{“hello”}; And scalar variables too int x{7};

25 Initializing a Vector

26 Vector Operations

27 Standard Iterator Operations

28 Iterator Invalidation
General rule: If you insert or remove elements into/from inside a container, any existing iterators are invalidated Start over! There are exceptions to this, though More on this later.

29 Random Access Iterators
string, vector, deque, and array support this pointer arithmetic array is new in C++11

30 Built-in Arrays Sized at compile time
Dimension must be a compile-time constant Can use range-based for loop but only in the scope in which the array is defined (ditto begin/end) int a[] = {1,2,3}; for (auto x: a) cout << x << ' '; // 1 2 3 cout << endl; int b[5] = {1,2,3}; for (auto x: b) cout << x << ' '; //

31 Pointers and Arrays Remember this!
Array names in expressions “decay” into a pointer to the 1st element Except when an operand to sizeof 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!

32 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; }

33 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 Not the most useful idiom, admittedly

34 Multi-dimensional Arrays
Don’t really exist! “Arrays of arrays” model int a[2][3] an array of 2 elements each element is an arrays of 3 ints what is sizeof(a[0])? sizeof(a[0]) = 3 * sizeof(int)

35 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; }

36 /* 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 */

37 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 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).

38 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; }

39 /* Output: sizeof(p): 8 sizeof(*p): 12 sizeof(1): 4 sizeof(2): 4
*/ 64-bit platform has pointer size 8.

40 Higher and Deeper Repeat the process on the 3-d array: int a[2][3][4];
int (*p)[3][4] = new int[2][3][4];

41 int a[][3][4] = {{{1,2,3,4},{5,6,7,8},{9,0,1,2}},
{{3,4,5,6},{7,8,9,0},{1,2,3,4}}}; int (*p)[3][4] = a; cout << "sizeof(p): " << sizeof(p) << endl; cout << "sizeof(p[0]): " << sizeof(p[0]) << endl; cout << "sizeof(p[0][0]): " << sizeof(p[0][0]) << 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; size_t t = sizeof(p[i][j]) / sizeof(a[i]); for (size_t k = 0; k < t; ++t) cout << "sizeof(" << p[i][j][k] << "): “ << sizeof(p[i][j][k]) << endl; }

42 sizeof(p): 8 sizeof(p[0]): 48 sizeof(p[0][0]): 16 sizeof(0x7fff606783f0): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff ): 16 sizeof(0x7fff606784a0): 16 sizeof(p[1]): 48 sizeof(0x7fff606784b0): 16 sizeof(0x7fff606784c0): 16 sizeof(0x7fff606784d0): 16

43 Arrays and Range-based for Loops
Iterates through top-level elements first just like we did in the previous examples Multidimensional arrays require using reference loop variables except on innermost (last) dimension to avoid the normal array-to-pointer decay

44 int a[][3] = {{1,2,3},{4,5,6},{7,8,9}}; for (const auto &row: a) { 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 */

45 Returning Heap Arrays Not often done
As usual, must return a pointer to the first element So… what is the signature of the function? “f is a function that returns a pointer to an array of 3 ints”

46 int (*f())[2] { return new int[7][2]; } int main() int (*p)[2] = f(); cout << sizeof(p[0]) << endl; // 8 cout << sizeof(p[0][0]) << endl; // 4 delete [] p;

47 std::array A “wrapper” around built-in arrays Provides:
a “first-class” object with value semantics they don’t decay to pointers passed by value to functions (i.e., copied) arrays of same size can be assigned, compared Provides: iterators (begin, end, random-access operations) compatibility with range-for loops size( ) method index range checking (with at( )) automatic zero-initialization Defined in <array>

48 enum {N = 5}; array<int, N> a = {1,2,3,4}; cout << sizeof(a) << endl; // 20 cout << a.size() << endl; // 5 for (auto x: a) cout << x << ' '; // cout << endl; array<int, N> b; b = a; assert(b == a); b[4] = 5; assert(b != a); for (auto x: b) cout << x << ' '; //

49 Dynamic Arrays with vector
// Shows how to easily read/print ints from a file #include <algorithm> #include <fstream> #include <iostream> #include <iterator> #include <vector> using namespace std; int main() { ifstream f("ints.dat"); auto b = istream_iterator<int>(f), e = istream_iterator<int>(); vector<int> v(b,e); copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout << endl; f.close(); }

50 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++

51 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.

52 RAII Using Objects to Manage Resources
“Resource Acquisition is Initialization” Memory is just one of many resources We treat all resources equally in C++: Have a constructor acquire them Have the destructor release them Example: file streams rarely need to explicitly close a file Example: raii.cpp RAII defines the scope of a resource’s lifetime. It’s handling is automatic.

53 Smart Pointers RAII + exposing the resource handle
Objects that emulate pointers They hold the real pointer but the wrapper object lives on the stack its destructor calls delete on the real pointer Overloaded operators: * ->

54 The Semantics of operator -> A Unique Operator!
It runs twice! First: it must return a “pointer-like thing” Next: operator-> is called again on that return value Eventually a raw pointer must be returned int main() { Foo f = {1,2}; FooWrapper fw(&f); cout << fw->x << '\n'; cout << fw->y << '\n'; } /* Output: returning a Foo* 1 2 */ struct Foo {int x; int y;}; class FooWrapper { Foo* pf; public: FooWrapper(Foo* p) : pf(p) {} Foo* operator->() { cout << "returning a Foo*\n"; return pf; } };

55 More Examples of operator ->
Creating a simple smart pointer SafePtr.cpp (generic version) smart.cpp (multi-level) unique_ptr (uniqptr1-3.cpp, deleter1.cpp) unique_ptrs are not copyable (but the are movable) shared_ptr (sharedptr.cpp, deleter2.cpp) shared_ptrs increment their reference count when copied And delete the raw pointer when count == 0 auto_ptr is deprecated.

56 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

57 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

58 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*)

59 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

60 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

61 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

62 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 0;} 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.

63 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 2

64 Review Specs for Program 2


Download ppt "CS 3370 – C++ String, Vectors, and Arrays"

Similar presentations


Ads by Google