C++

Input/Output

<< input operator
>> output operator
cin.fail();
cin.eof();
while(true) {
    if(!(cin >> i)) {
        if(cin.eof()) break;
        else {
            cin.clear(); //lowers the flag
            cin.ignore();
        }
    }
    else cout << i << endl;
}

Streams

cout << hex << i;

To read an entire line, use getline(istream, s) to read from the first unread char in the input stream until we hit a newline.

#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
int main() {
    ifstream f("suite.txt");
    string s;
    while(f >> s) cout << s << endl;
    istringstream str(s);
    int tmp;
    while(str >> tmp) cout << tmp << endl;
    return 0;
}
In C In C++
equality strcmp s1 == s2
inequality strcmp s1 != s2
comparisson strcmp s1 < s2
length strlen s1.length()
concatenation strcat s1 + s2
void printSuiteFile(string fileName="suite.txt") {
    ifstream myfile(name.c_str()); //name must be a C style string
    string s;
    while(myfile >> s) cout << s << endl;
}
  1. optional parameters must appear last
  2. not allowed to follow a default argument with a non-default argument

Overloading

int nagate(int a) { return -a}
int negate(bool a) { return !a; }

It is not enough for two function to only differ on the return type

Declaration and Definition

Pointers

int n = 5;
int *p = &n;    //p contains the address of n
cout << p;      //print out the address
cout << *p;     //print the contents of thing p points to
int **p;        //pointer to a pointer to an int;
pp = &p;
**p = 10;

Arrays

An array is not a pointer! The name of an array is shorthand for the address of the first element of the array.

int a[] = {1,2,4,8};
*a == a[0];
*(a + 1) == a[1];

Structure

struct Node {
    int n;
    Node next;  //wrong, the compliler dose not know the size of the structure
    Node *next;
};  //Do not forget the ;

Constants

const int maxgrade = 100;

A constant definition must be initialized

const int* p = &n;

p is a pointer to a constant int

p = &m; \\valid
*p = 7; \\invalid
int* const p = &n;

p is a constant pointer to an int

p = &m; \\invalid
*p = 7; \\valid
const int* const p = &n;

p is a constant pointer to a constant int

Passing Parameter

void inc1(int n) { n ++; }
void inc2(int *n) { *n ++; }
void inc3(int &n) { n ++; }

Reference

int y =10;
int &z = y; //z is a reference to y
z = 12;

A reference is like a constant pointer with automatic dereferencing. Reference has no identity of its own. z mimics y.

  1. cannot leave a reference uninitialized.
  2. a reference must be initialized to something that has an address.
  3. cannot create a reference to a pointer. (int &*x=)
  4. cannot create a reference to a reference. (int &&x=)
  5. cannot create a array of reference. (int &x[3] = {y, y, y})
struct ReallyBig{};
int f(ReallyBig &rb){};
  1. no copy
  2. changes visible to caller
  3. automatic dereferencing

Advice: Prefer to pass by const reference for anything that is larger than an int.

Dynamic Memory

C++ allocates using new, deallocates using delete

int *n = new int;
cin >> *n;
int *arr = new int[*n];
delete [] arr;
delete n;

Local variable allotted space on the stack, space is automatically reclaimed when variables go out of scope.

Node getMeANode() {
    Node;
    return n;
}

inefficient, returns value is copied.

Node* getMeANode() {
    Node n;
    return &n;
}

Really bad: returing a pointer to a stack allocated variable ```C++ Node* getMeANode() { Node *np = new Node; return np; } Good: Node is allocated in heap

Operator Overloading

We can give meaning to C++ operators for any new type we create

struct vec {int x,y;}
vec operator + (const vec &a, const vec &b);

Overloading input and output operators

ostream &operator << (ostream &out, const grade &g) {
    out << g.theGrade << "%";
    return out;
}
istream &operator >> (istream &in, const grade &g) {
    in >> g.theGrade;
    if(g.theGrade > 100) g.theGrade = 100;
    if(g.theGrade < 0) g.theGrade = 0;
    return in;
}

Preprocessor

Source code -> Preprocessor -> Compiler -> Assembler -> Linker

#include <iostream> //look standard C++ lib (/usr/lib/c++)
#include "vector.h" //look the lib in current directory
#define VAR VALUE   //preprocessor variable with VALUE (default is empty string)
g++ -DX=15 define.cc

X will be defined as 15

#ifdef X
    block of code
#endif

Break your program into: * interface file (.h) type definitions and funciton headers * implementation file (.c/.cc/.cpp)

Note:

* Never complie header files
* Never include .cc files

Separate Compilation: Ability to compile individual pieces of a program and the combine them.

g++ -c main.cc      //just compile, produce an object file (.o)
g++ -c vector.cc
g++ main.o vector.o //linker acts as the mathchmakers

Global Variables

In .h file

extern int globalvar;   //just declaration

In .cc file

int globalvar;  //definition

Include Guard

#ifndef __HEADER_H__
#define __HEADER_H__
...
#endif

Advice: Always place an include guard Advice: Never put "using namespace std;" in your header file Advice: Always refer cout as std::cout etc.

Templates

A class parameterized on one or more types.

template <typename T> class Node {
    T data;
    Node <T>* next;
    public:
    Node(T data, Node <T>* next) : data(data), next(next) {}
    T getData const {return data;}
    Node <T>* getNext() const {return next;}
};
Node <int> *intList = new Node <int> (1, new Node <int> (2, NULL));
Node <char> *charList = new Node <char> (‘a’, new Node <char> (‘b’, NULL));
Node < Node <int> > *linkedListofList; \\not >> for c++ 03 because >> is overloaded

STL: Standard Template Library

Dynamic Length Arrays: vector

for(int i = 0; i < v.size(); i ++)
    cout << v.at(i) << endl;    \\range checked acces
v.pop_back();   //remove last element
for(vector <int>::iterator i = v.begin(); i != v.end(); i ++);
for(vector <int>::reverse_iterator i = v.rbegin(); i != rend(); i ++);

v.end() points ONE PAST the last element of the array

Lookup table: map template parameterized on 2 types

#include <map>
using namespace std;
map < <string> <int> > m;
int main() {
    m["abc"] = 5;
    m["xyz"] = 10;
    cout << m["abc"] << endl;
    m.erase("abc");
    m.count('def");
}

iterator returns items in sorted key order.

Compilation Dependencies

When to include vs When to forward declare

In a.h

class A{};

In b.h

#include "a.h"
class B: public {};

In c.h

#include "a.h"
class C {A myA;}

In d.h

class A;
class D {A* pMyA;}

static_cast

double d = static_cast <double> (m);

Sensible casts

Book *pb = new Textbook();
Textbook *tp = static_cast <Textbook*> (pb);

Since we know that bp points to a Textbook, it is sensible to use static_cast, static_cast is unchecked. If your assumption was wrong, you get undefined behaviour.

reinterpret_cast

Weird conversions. Allow conversion of pointer to a pointer of any type.

student *s = reinterpret_cast <studnet*> (&v);

Behaviours is compiler dependent

const_cast

Get or take away the const property

void g(int* p) {}
void f(const int* q) {
    g(q);   //compiler error
    g(const_cast <int*> (q));
}

Behaviour undefined if q changes p

dynamic_cast

vector <book*> myBooks;
book* b = myBooks[num]; //should not staic_cast because we do not know what b points to
Textbook *t = dynamic_cast<Textbook*> (b);
if(t) {...}
else cout << "not Textbook" << endl;

Tentatively cast and see if it succeeds. If b points to a Textbook, after the cast, t is a Textbook pointer to the object. If the cast fails, t is set to NULL.

To use dynamic_cast, the class hierarchy must have at least one virtual method.

  1. only classes with at least one virtual method have a virtual table (vtable).
  2. instances of such classes keep a pointer to this vtable

RTTI: Runtime Type Information

void whatIsIt(Book* b) {
    if(dynamic_cast <Comic*> (b)) cout << "Comic" << endl;
    else if(dynamic_cast <Textbook*> (b)) cout << "Textbook" << endl;
}
  1. use dynamci_cast to make decisoin based on RTTI
  2. high coupling (poor design)
  3. brittle (changes to the hierarchy, requires me to search to find all places which use RTTI)
  4. better use virtual (visitor design pattern)
Book &b = ...;
Comic &c = dynamic_cast <Comic&> (b);

Error Handling

In C, need to keep checking whether an error has occurred.

Error Condistions in C++

In C++, if an error occurs, an exception is raised/thrown, default behaviour is terminate the program. If you do not want the program to terminate, then hanlde/catch then the exception.

See sample code callchain.cc

When an exception is thrown, the call stack begins to w=unwind, looking for a suitable catch block.

out_of_range is a class -- you throw objects of the exception class.

Error Recovery can be multi-step process. A handler could do part of the recovery and then ask a function higher in the call stack to complete the recovery.

try{...}
catch(someErroType e) {
    //Partially recovery
    throw someOtherExcetion();
}
//catches exceptions of type someOtherException or any subclass

Option 1. throw

Option 2. throw e

Advice: use throw

All C++ exceptions inherit from a calss named "exception". Exception do not need to inherit from any base class.

class BadInput {};
try {
    int n;
    if(!(cin >> n)) {
        throw BadInput();
    }
    catch(BadInput &bi) {
    }

Exception can be caught by reference

Advice: catch by reference; To rethrow: just throw.

Book* p = new Comic(...);
Book* q = new Comic(...);
try{ *p = *q;}
catch(bad_cast &m) {cout <<"oops" << endl;}
virtual Comic &Comic::operator=(const Book &other) {
    Comic &cother = dynamic.cast<Comic &>(other);
    title = cother.title;
    ...;
    return *this;
}

if dynamic_cast fails, bad_cast exception thrown

void f() {
    MyClass* p = new MyClass;
    MyClass q;
    g();
    delete p;
}

Memory leak if g throws!

Exceptions are meant to be recored from. Our code needs to be exception safe: even if an exception occurs, it should not leave a scar (memory leak, dangling pointer)

C++ promise: if an exception occurs, then during stack unwinding, doors for stack allocated objects will be called.

To make f exception save:

void f() {
    MyClass* p = new MyClass;
    MyClass q;
    try{g();}
    catch(...) {
        delete p;
        throw;
    }
    delete p;
}

Tedious

Advice: prefer allocating objects on the stack

Never let a destructor throw an exception * destructors are called during stack unwinding (where there is already a live exception) * if two exceptions are live simultaneously, program terminates

C++ idiom: RAII (Resource Acquisition Is Initialization)

Every resourse should be wrapped in a stack-allocated object, whose job is to delete/release the resource.

ifstream f("file.txt");

file is opened when f is initialized.

file is released when

Treat heap allocated memory as a resourse C++ standard template library provide

class auto_ptr

void f() {
    auto_ptr <MyClass> P(new MyClass);
    MyClass q;
    g();
}

Problem:

class c {};
auto_ptr<c> p(new c);
auto_ptr<c> q = b;

If p and q point to the same object, when their destructors run, it will lead to a double free. When an auto_ptr is assigned to another, q steals the thing p pointed to, p is set to NULL.

Excepttion Safety: 3 Levels

  1. Basic Guarantee: If an exception occurs, then program will be in a valid state (no memory leak, no dangling pointer).
  2. Strong Guarantee: If an exception occurs while executing a function f, then the state of the program is as if f never ran.
  3. No Throw Guarantee: Function never throws an excetion, it always achieves its goal.
class A {};
class B {};
class C {
    A a;
    B b;
    public:
    void f() {
        a.g();
        b.h();
    }
};

f: exception safety level?

Assume g and h have no non-local side effects

void f() {
    A atemp = a;
    B btemp = b;
    atemp.g();
    btemp.h();
    a = atemp;
    b = btemp;
}

No strong guarantee, because b = btemp might throw.

Use Pimpl Idiom:

struct Cimpl { A a; B b; }
class C {
    auto_ptr <Cimpl> pImpl;
    f() {
        auto_ptr <Cimpl> tmp(new Cimpl(* pImpl));
        temp->a.g();
        temp->b.h();
        std::swap(pImpl, tmp);
    }
};