pointers & references 1-22-2013
Inline Functions References & Pointers Arrays & Vectors HW#1 posted due: today Quiz Thursday, 1/24
// point.h #ifndef POINT_H_ #define POINT_H_ #include <iostream> using namespace std; // Represents a 2D Point class Point { public: Point(int newx, int newy): x(newx), y(newy) {}; Point() : x(0), y(0) {}; int getx() const {return x;} int gety() const {return y;} bool operator<(const Point& other) const; bool operator==(const Point& other) const; friend ostream& operator<<(ostream& os, const Point& p); private: int x; int y; }; #endif
// point.cpp #include <iostream> #include "point.h" using namespace std; // p1 < p2 if (p1.x < p2.x )or ((p1.x equals p2.x) and p1.y < p2.y) bool Point::operator< (const Point& other) const { return (x < other.x) ((x == other.x) && (y < other.y)); } // p1 is "equal to" p2 iff (p1.x) equals (p2.x) and (p1.y) equals (p2.y) bool Point::operator== (const Point& other) const { return (x == other.x) && (y == other.y); } ostream& operator<< (ostream& os, const Point& p) { os << "[" << p.x << "," << p.y << "]" << endl; return os; }
Item 3:* Use const whenever possible We ve seen several examples of this in our member functions, such as ==, >>, etc. * Effective C++, 3 rd Edition, p. 17
Item 4:* Make sure that objects are initialized before they re used. example: suppose you have the following in C++ int x; question: does x have a random value or is it zero? answer: in some contexts, x is guaranteed to be initialized (to zero in this case), but in others it is not (e.g. local variables are not automatically initialized). solution: always initialize variables yourself * Effective C++, 3 rd Edition, p. 26
Item 4:* Make sure that objects are initialized before they re used. example: class Point { private: int x, y; } application program: int main() { } Point p; // calls default constructor return 0; The purpose of a constructor is to initialize all data members (instance variables). You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.
implicit (code in class definition, e.g. Point) class Point { public: int getx() const { return x; } // }; explicit (code in implementation file, e.g. Time) inline void Time::read(istream& in) { in >> hours; in.get(); in >> minutes: }
An inline specifier for a function f is a suggestion to the compiler that it should attempt to replace each function call to f with the code body of f. FAQ 13.05 what are some performance considerations with inline functions? 1. They might improve performance, or they might make it worse. 2. They might cause the size of the executable to increase, or they might make it smaller.
from Google C++ style guide It is important to know that functions are not always inlined even if they are declared as such Define functions inline only when they are small, say, 10 lines or less. Constructors, accessors & mutators and other short performance-critical functions are good candidates. Don t inline functions that contain loops or switch statements recursive functions be very careful before inlining a destructor
Declaring a reference variable is a way to give an object an alternative name. Example: double& rx = x; both x and rx refer to the same object. Note that rx itself is not an object it s a referent to another object. Consider the following assignment statement rx = 15; This changes x s value to 15; rx is unchanged (still a referent to x)
By default, functions are called by value. A copy of the arguments are made and stored into objects corresponding to the parameters. Any changes made to the parameter values do not affect the original argument objects. If a parameter is declared to be a reference type, then: The parameter is bound to the argument. Any change made to the parameter is made to the original argument.
Pass-by-Value: void swap (int x, int y) { int temp = x; x = y; y = temp; } int main() { x = 42 y = 24 int a = 42, b = 24; swap(a,b); cout << a << b << endl; } // prints 42 24 Pass-by-Reference: void swap (int &x, int &y) { int temp = x; x = y; y = temp; } int main() { int &x = a int& y = b int a = 42, b = 24; swap(a,b); cout << a << b << endl; } // prints 24 42
Class types may occupy several storage locations in memory. Passing a class type object by value is inefficient. By declaring the parameter to be a const reference, function can access the value of the argument, but not change it.
// given a character c and a string s, counts and returns // the number of times c occurs in s (possibly zero) int count_occurences(char c, const string& s) { int count = 0; for (int i = 0; i < s.size(); i++) { if (c == s[i]) count++; } return count; }
More examples class Point { public: Point(int i, int j) : x(i), y(j) { } Point() : x(0), y(0) { } int getx() const { return x; } bool operator<(const Point& other) const; friend ostream& operator<<(ostream& os, const Point& p);
A pointer is a variable whose value is the memory address of an object (&obj) means the memory address of obj (*p) means the object that pointer p is currently pointing to int k = 25; // k s value is the integer 25 int *p = &k; // p s value is the memory address of k *p = -7 // changes k (p is unchanged) cout << k <<, << (*p) << endl;
Reference version: void swap (int &x, int &y) { int temp = x; x =y; y = temp; } int main() { int &x = a int& y = b int a = 42, b = 24; swap(a,b); cout << a << b << endl; } // prints 24 42 Pointer version: void swap (int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int main() { x = &a y = &b int a = 42, b = 24; swap(&a,&b); cout << a << b << endl; } // prints 24 42
NEVER dereference the NULL pointer! int *p; p = NULL; cout << *p; /* but p is not pointing to anything! */ *p = 42; /* ARRRRRRGGGGHHH! core dump */ if (p!= NULL) /* fail-safe programming */ cout << *p;
int x = 5; int *px = &x; int& rx = x; x and px are separate variables in memory; rx is not A reference must be assigned a value when it is declared; after that, it cannot be changed. A pointer can be changed. A pointer can point to NULL while reference cannot have the value NULL. You can't take the address of a reference like you can with pointers Pointer arithmetic is allowed (e.g. px = px + 2). There's no "reference arithmetic"
As a general rule, Use references in function parameters and return types to define attractive interfaces. Use pointers to implement algorithms and data structures.
For a type T, T[size] is the type array of size elements of type T ; elements are indexed from 0 to size-1 The number of elements (size) must be a constant expression Arrays can be initialized with an initialization list An array of objects is initialized by calling the default constructor for the object (unless an initialization list is provided). int c[3] = {127, 255, 212}; float temperature[7]; // might not be initialized Point triangle[3]; // calls Point::Point()
Arrays have a fixed, predetermined size Arrays don t know their size Arrays don t support the usual operators (assignment, ==, <, etc.) It is not easy to have a function return a copy of an array Recommendation: use container classes
FAQ 28.01: What are container classes? Answer: Containers are objects that hold other objects. Examples include vectors, lists, queues, and sets, among others. FAQ 2.15: What are the basics of using container classes? Answer: Templates are one of the most powerful code reuse mechanisms in C++. The most common use for templates is for containers. e.g. vector<t>, list<t>, set<t>
An enhancement of the array. Can be used like an array: access a value with an index, e.g. x = v[i]; v[j] = z; The size of a vector is not constant it can grow or shrink A vector knows its current size Additional capabilities: Insert an element at a specified position Remove an element from a specified position Overloads the assignment operator (=) and comparisons: <, <=, ==, >, >=,!=, etc. Functions can return a vector
The C++ standard library contains standard template classes (known as the Standard Template Library, or STL). Some methods include: constructor copy constructor destructor assignment op= size() push_back() cf. Table 5.1, Maciel
general form: vector<t> where T is a type vector<double> stats; // vector of doubles vector<float> v(10); // vector of 10 floats vector<string> file_contents;
vector<point> polygon; Point p1(100,200); Point p2(150,150); Point p3(150,50); Point p4(75,90); polygon.push_back(p1); polygon.push_back(p2); polygon.push_back(p3); polygon.push_back(p4); for (int i = 0; i < polygon.size(); i++) cout << polygon[i] << endl;
preface.txt -------------------------------------------------- 1 After a few computer science courses, students may start to 2 get the feeling that programs can always be written to 3 solve any computational problem. Writing the program may 4 be hard work. For example, it may involve learning a 5 difficult technique. And many hours of debugging. But 6 with enough time and effort, the program can be written. 7 8 So it may come as a surprise that this is not the case: 9 there are computational problems for which no program -------------------------------------------------- next previous open quit ------- command: o file: introduction.txt
void run_file_viewer() main function of the file viewer displays the given number of lines asks user what to do next: q o quit open a text file vector<string> v_document_lines data structure for storing the document s lines
void run_file_viewer() { vector<string> v_document_lines; string file_name; open_file(file_name, v_document_lines); while (true) { // while command is not 'quit' display(file_name, v_document_lines); cout << "command: "; char command = '-'; cin.get(command); cin.get(); // '\n' switch (command) { case 'q': return; case 'o': { open_file(file_name, v_document_lines); } // end case o } // end switch } // end while } // end run_file_viewer
void display(const string & file_name, const vector<string> & v_document_lines) { cout << endl << file_name << endl; string long_separator(50, '-'); cout << long_separator << endl; for (int i = 0; i < v_document_lines.size(); ++i) cout << setw(3) << i+1 << " " << v_document_lines[i] << endl; cout << long_separator << endl << " open quit" << endl; string short_separator(8, '-'); cout << short_separator << endl; } // end display
For Thursday, read Maciel, Chapter 5 Quiz #1 on Thursday, 1/24, in class